multiple definitions....

L

lbj137

I have two files: A.c and B.c. In both files I define a global
variable, int xxxx; When I compile with a green hills compiler (and
also i think with a GNU compiler) I get no errors or warnings. Only
when I initialize xxxx to two different values in A.c and B.c
respectively do I get a 'multiple definitions' error. I was under the
impression that I would get such an error even without initializing
xxxx twice, simply because i am (ostensibly) allocating memory for it
twice. what is going on here?
 
L

Lew Pitcher

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I have two files: A.c and B.c. In both files I define a global
variable, int xxxx; When I compile with a green hills compiler (and
also i think with a GNU compiler) I get no errors or warnings. Only
when I initialize xxxx to two different values in A.c and B.c
respectively do I get a 'multiple definitions' error. I was under the
impression that I would get such an error even without initializing
xxxx twice, simply because i am (ostensibly) allocating memory for it
twice. what is going on here?

While this is not strictly a C issue (at least I don't think it is), and thus
is off topic here, I think that a short explanation might help.

Compilers can be smart. If they see that a global is allocated but not
initialized, they can just make space for it in their map of where data is
stored, but not actually generate the instructions/data to fill in the space.

When a global is allocated by more than one translation unit, the linker (or
what ever performs that task) can attempt to resolve the 'space left for the
global' into a usable (load image, execution image, 'core' ) form.

When both tu initialize the global, the linker can't decide which
initialization to use, and you get a multiple definition error.

When only one tu initializes the global, the linker uses that tu's allocation,
and fills in the blanks into the tu that didn't initialize the global.

When neither tu initialize the global, the linker allocates it directly, and
fills in the blanks in both of the tu's.

In other words, you can allocate a global in multpile translation units, but
you are only permitted to give it an initial value in one of those TUs.

- --
Lew Pitcher

Master Codewright & JOAT-in-training | GPG public key available on request
Registered Linux User #112576 (http://counter.li.org/)
Slackware - Because I know what I'm doing.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)

iD8DBQFCshw0agVFX4UWr64RAtdeAJ9GRAARlW4hIHJmCr3JBWVmacGRFACbBPVp
dJ46PHXfhoXTfNx4KEjSXmM=
=z5/3
-----END PGP SIGNATURE-----
 
J

Jean-Claude Arbaut

Le 17/06/2005 01:32, dans
(e-mail address removed), « (e-mail address removed) »
I have two files: A.c and B.c. In both files I define a global
variable, int xxxx; When I compile with a green hills compiler (and
also i think with a GNU compiler) I get no errors or warnings. Only
when I initialize xxxx to two different values in A.c and B.c
respectively do I get a 'multiple definitions' error. I was under the
impression that I would get such an error even without initializing
xxxx twice, simply because i am (ostensibly) allocating memory for it
twice. what is going on here?

Make your variables "static", or use "extern" and one initialization.

The standard allows multiple declarations, but only one initialization (see
section 6.2.2 of ISO 9899-1999). If there is no "static" or "extern"
specifier, "extern" is assumed, hence there is no problem in your program
if you initialize one of your variables or none. I think it's preferable
to explicitly use "extern", to remember there are other declarations.

The standard says both variables represent the same object, and in practice,
they share data in memory. I don't know if the standard
allows you use different types (say, "int c" and "char c" in different
files), but at least it works in my version of gcc, and both variables
share the same space, again.
 
J

Jean-Claude Arbaut

Le 17/06/2005 02:59, dans BED7ED1D.4F22%[email protected],
« Jean-Claude Arbaut » said:
The standard allows multiple declarations, but only one initialization (see
section 6.2.2 of ISO 9899-1999). If there is no "static" or "extern"
specifier, "extern" is assumed, hence there is no problem in your program
if you initialize one of your variables or none. I think it's preferable
to explicitly use "extern", to remember there are other declarations.

The standard says both variables represent the same object, and in practice,
they share data in memory. I don't know if the standard
allows you use different types (say, "int c" and "char c" in different
files), but at least it works in my version of gcc, and both variables
share the same space, again.

About different types: the standard says the identifiers represent the same
object, however section 6.7 says

"All declarations in the same scope that refer to the same object or
function shall specify compatible types."

So same object doesn't necessarily mean same type ? (otherwise why enforce
that restriction ?). That would mean the "int c","char c" example is
allowed.
 
J

Jean-Claude Arbaut

Le 17/06/2005 02:41, dans [email protected],
« Lew Pitcher » said:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1



While this is not strictly a C issue (at least I don't think it is), and thus
is off topic here, I think that a short explanation might help.

It seems to me that's a question on declaration, so perfectly on-topic.
 
J

Jack Klein

I have two files: A.c and B.c. In both files I define a global
variable, int xxxx; When I compile with a green hills compiler (and
also i think with a GNU compiler) I get no errors or warnings. Only
when I initialize xxxx to two different values in A.c and B.c
respectively do I get a 'multiple definitions' error. I was under the
impression that I would get such an error even without initializing
xxxx twice, simply because i am (ostensibly) allocating memory for it
twice. what is going on here?

Your code generates undefined behavior, and anything can happen, the C
standard washes its hands and takes no responsibility for the results.

C has rules about external declarations of functions or objects in a
program. There are only two of them and they are quite simple:

1. If the external object or function is not actually used by the
program, there may be exactly 0 or 1 definitions of it in the program.

2. If the external object is accessed or the external function is
called, there must be exactly 1 definition of it in the program.

In your case, if you define the same object or function with external
linkage in two different translation units, you break both of these
rules, producing undefined behavior. At that point, as far as C is
concerned, anything can happen. Once you define the object in two
different translation units in the same program, the program is no
longer valid C, so the fact that you can change the (undefined)
behavior by breaking the rule in different ways is not a C language
issue.
 
L

Lawrence Kirby

I have two files: A.c and B.c. In both files I define a global
variable, int xxxx; When I compile with a green hills compiler (and
also i think with a GNU compiler) I get no errors or warnings. Only
when I initialize xxxx to two different values in A.c and B.c
respectively do I get a 'multiple definitions' error. I was under the
impression that I would get such an error even without initializing
xxxx twice, simply because i am (ostensibly) allocating memory for it
twice. what is going on here?

Multiple definitions in different translation units produces undefined
behaviour according to the C standard, it is not a constraint violation.
What that means is that it is an error in the program but not one that the
compiler is required to diagnose. But it can if it wants to.

The reason for this latitude is that the linkers provided with some
platforms do diagnose, and some don't and some diagnose in specific
circumstances. These linkers may have to support languages other than C
and the C designers wanted to make the language as easy to implement as
possible i.e. work with the existing tools (like linkers) that were out
there.

In your particular example the linker can link 2 definitions of the same
object without an initialiser. But when you gave it 2 initialisers there
was a conflict which it couldn't resolve (it can't initialise to 2 values
at once) so it complained. This isn't C defined behaviour, it is just the
way the linker works but it is allowed by C. However the program is
still faulty and may well fail on some other compiler/linker.

Lawrence
 
C

Chris Torek

Le 17/06/2005 02:59, dans BED7ED1D.4F22%[email protected],
About different types: the standard says the identifiers represent the same
object, however section 6.7 says

"All declarations in the same scope that refer to the same object or
function shall specify compatible types."

So same object doesn't necessarily mean same type ? (otherwise why enforce
that restriction ?). That would mean the "int c","char c" example is
allowed.

The reason for the "compatible type" wording is that things
like this are allowed:

extern int a[];
extern int a[100];

Note that these are not the *same* type. The first one is
"array of unspecified size of int", or as I prefer to write
it, "array ? of int". The second one is "array 100 of int".
These types are compatible, but not identical.

(Similar rules hold for function declarations. One can write:

int f();
int f(int, char *);

and the two types are clearly not identical, yet are compatible.
But watch out:

int g(char);
int g(c) char c; { ... }

effectively re-declares g() with a type that is *not* compatible
with the earlier declaration. I believe a diagnostic is not
required, however.)
 
J

Jean-Claude Arbaut

Le 18/06/2005 07:00, dans (e-mail address removed), « Chris Torek »
The reason for the "compatible type" wording is that things
like this are allowed:

That's right.

And what about "int c" "char c" in two separate files ?
I'm still not absolutely sure the standard disallows this.
 
D

Dave Thompson

Le 17/06/2005 02:59, dans BED7ED1D.4F22%[email protected],

See 6.9.2 also. The standard allows one _definition_ of an object (or
function) name with external linkage and multiple declarations that
refer to it. A declaration with an initializer is always a definition.
A declaration with no initializer and 'extern' is only a declaration.
An object declaration with no initializer and no storage-class
specifier is a 'tentative definition' which magically is turned into a
definition with value zero unless overridden by a definite definition
in the same translation unit which is of course also a definition. And
doing either of those in more than one t.u. is Undefined Behavior.
(This particular U.B. is caught by *some* implementations.)

For functions it is simpler because the syntax differs. A declaration
with just a semicolon is just a declaration; something that looks
syntactically like a declaration followed by a braced block aka
compound statement is a definition. 'extern' is always redundant,
though some people consider it good style.
About different types: the standard says the identifiers represent the same
object, however section 6.7 says

"All declarations in the same scope that refer to the same object or
function shall specify compatible types."

So same object doesn't necessarily mean same type ? (otherwise why enforce
that restriction ?). That would mean the "int c","char c" example is
allowed.

Scope only applies within a translation unit (preprocessed source
file), and automatic variables may not be redeclared within the same
scope at all, so this actually applies only to multiple declarations
at file-scope of a variable or function -- or multiple declarations of
an 'extern' variable within a block, which is pretty obscure and
usually considered bad style. Yes that variable or function always has
the same type; that's precisely why the declarations must be
compatible -- and since 6.7p4 is a constraint, if your code violates
it the compiler must issue a diagnostic. Compatible, rather than
identical, allows some of the declarations to _omit_ some information:
int a[20];
int a[10]; // ERROR: incompatible
int a[]; // compatible
void f (); // old-style doesn't specify parameters
void f (int a, char * b); // compatible
int f (); // ERROR: incompatible

This may not seem useful because one doesn't normally think of just
writing more than one declaration for the same thing. There are two
places it is, though. First, pretty rare, is if there is a dependency
cycle in initializers so that you must declare some object and use it
before you can write its initializer. The other, much more common, is
when you have a header file that declares the functions and (possibly)
objects "exported" from a module for use by other t.u.s. Since a
definition is also a declaration, if you #include that header
(typically .h) into the source file that implements those entities
(.c) then the compiler will warn you of any mistakes where an object
or a prototyped function does not agree with the promised interface.

What applies between t.u.s is linkage. If a given name is declared in
different t.u.s with external linkage, both/all declarations (and the
code using them) refer to the same object or function. If an object X
actually has (is defined with) type A, but you access it through an
lvalue having an incompatible type B (from a wrong declaration) it is
Undefined Behavior (which is not required to be and rarely is
diagnosed) except for a few special cases in 6.5p7 and 6.5.2.3p5. And
even for those (former) it is possible that the stored representations
for some values of type A may be trap representations for type B and
fetching such also causes Undefined Behavior. But if B is unsigned
char, or plain char on a system where (as on many) that is unsigned,
*that* access is safe -- although it may or may not be useful.

- David.Thompson1 at worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,297
Messages
2,571,536
Members
48,284
Latest member
alphabetsalphabets

Latest Threads

Top