declare vs define of global variables

B

Brian Sammon

According to my programming textbook, "int a;" at the top level of a
file is a definition which shouldn't go in a header file.
However, I'm running into a lot of online documentation that treats that
kind of statement as a declaration that can be in a header file used in
multiple compilation units.
Which of these is correct? Is this something that has changed between
different standards?
 
J

Jack Klein

According to my programming textbook, "int a;" at the top level of a
file is a definition which shouldn't go in a header file.
However, I'm running into a lot of online documentation that treats that
kind of statement as a declaration that can be in a header file used in
multiple compilation units.
Which of these is correct? Is this something that has changed between
different standards?


What kind of online documentation? What reason do you have to trust
its quality? If this documentation talks about using a declaration
like:

int a;

....without either the 'static' or 'extern' keywords at file scope, the
documentation is just plain wrong, and nothing has changed in
different versions of the C standard in this regard.

At file scope a definition like:

int a; /* no initializer */

....is called a 'tentative definition'. The identifier 'a' is declared
with file scope to have static storage duration, int type, and
external linkage. There may be more than one tentative definition for
the same identifier at file scope, as long as they all apply to the
same object type:

When there is a tentative definition in the file, one of two things
happens.

1. There is a later definition with an initializer (called an
'external definition'):

int a = 42;

2. There is no external definition, that is file scope declaration
with an initializer. In this case, at the end of the translation
unit, the compiler will act as though an external definition with an
initializer of 0 existed.

According to the C standard, you produce undefined behavior and C
takes no responsibility for the results by defining an object with
external linkage in multiple translation units. The standard states
that for each external object that is actually referenced in a
program, there must be exactly one definition.

It just so happens that there are some compiler/linker combinations
that allow this, as long as no more than one source file contains an
initializer for the object. It also happens that there are other
compiler/linker combinations that will reject the program even if none
of the source files contains an initializer.

In any case, it is specifically invalid and non-portable.
 
B

Bradley Bungmunch

According to my programming textbook, "int a;" at the top level of a
file is a definition which shouldn't go in a header file.
However, I'm running into a lot of online documentation that treats that
kind of statement as a declaration that can be in a header file used in
multiple compilation units.
Which of these is correct? Is this something that has changed between
different standards?


extern int a; /* an allusion to a - it tells the compiler to look
elsewhere for the definition - that's what you'd expect in a header
file *./

int a; /* a tentative definition or an allusion - it's up to the
compiler to decide on the basis of what's elsewhere in the source file
*/

int a=0; /* a real definition */


ANSI, K&R, and Unix all have different strategies for resolving
tentative definitions, allusions, and real declarations.




=====================



Pussie sHaveMo
reFunMeow MeowMeowPus
siesHaveMore FunMeowMeowMeo
wPussiesHaveMo reFunMeowMeowMeo
wPussiesHaveMor eFunMeowMeowMeowP
ussiesHaveMoreFu nMeowMeowMeowPussi
esHaveMoreFunMeo wMeowMeowPussiesHav
eMoreFunMeowMeowM eowPussiesHaveMor
eFunMeowMeowMeowP ussiesHaveMoreFunM
eowMeowMeowPussie sHaveMoreFunMeowMe owMeowPus
siesHaveM oreFunMeowMeowMe owPussiesHaveMore FunMeowMeowMe
owPussiesHave MoreFunMeowMeowM eowPussiesHaveM oreFunMeowMeowM
eowPussiesHaveM oreFunMeowMeow MeowPussiesHa veMoreFunMeowMeow
MeowPussiesHave MoreFunMeow MeowMeow PussiesHaveMoreFun
MeowMeowMeowPussi esHa veMoreFunMeowMeowMe
owPussiesHaveMoreF unMeowMeowM eowPussiesHaveMoreFu
nMeowMeowMeowPussie sHaveMoreFunMe owMeowMeowPussiesHav
eMoreFunMeowMeowMeo wPussiesHaveMoreFu nMeowMeowMeowPussie
sHaveMoreFunMeowMeo wMeowPussiesHaveMoreFu nMeowMeowMeowPussi
esHaveMoreFunMeowM eowMeowPussiesHaveMoreFu nMeowMeowMeowPuss
iesHaveMoreFunMe owMeowMeowPussiesHaveMoreFu nMeowMeowMeowP
ussiesHaveMor eFunMeowMeowMeowPussiesHaveMore FunMeowMeow
MeowPussi esHaveMoreFunMeowMeowMeowPussiesHave MoreF
unMe owMeowM eowPuss
iesHave MoreF unMeowMeowM
eowPussies Ha veMoreFunMeo
wMeowMeowP us si esHaveMoreFu
nMeowMeowM eow Pus siesHaveMore
FunMeowMeo wMeow Pussi esHaveMoreFu
nMeowMeow MeowPu ssiesH aveMoreFun
Meow MeowMeow Pussie
sHaveMoreFunMeowMeowMeowPussiesHaveM
oreFunMeowMeowMeowPussiesHaveMo
reFunMeowMeowMeowPussies
 
B

Bradley Bungmunch

What kind of online documentation? What reason do you have to trust
its quality? If this documentation talks about using a declaration
like:

int a;

...without either the 'static' or 'extern' keywords at file scope, the
documentation is just plain wrong, and nothing has changed in
different versions of the C standard in this regard.

At file scope a definition like:

int a; /* no initializer */

...is called a 'tentative definition'. The identifier 'a' is declared
with file scope to have static storage duration, int type, and
external linkage. There may be more than one tentative definition for
the same identifier at file scope, as long as they all apply to the
same object type:

When there is a tentative definition in the file, one of two things
happens.

1. There is a later definition with an initializer (called an
'external definition'):

int a = 42;

2. There is no external definition, that is file scope declaration
with an initializer. In this case, at the end of the translation
unit, the compiler will act as though an external definition with an
initializer of 0 existed.

According to the C standard, you produce undefined behavior and C
takes no responsibility for the results by defining an object with
external linkage in multiple translation units. The standard states
that for each external object that is actually referenced in a
program, there must be exactly one definition.

It just so happens that there are some compiler/linker combinations
that allow this, as long as no more than one source file contains an
initializer for the object.
A but it's a little bit more complex than that. K&R C says if you put
extern first then the presence or absence of an initializer makes no
difference - it's always an allusion.

It also happens that there are other
compiler/linker combinations that will reject the program even if none
of the source files contains an initializer.

In any case, it is specifically invalid and non-portable.


=====================



Pussie sHaveMo
reFunMeow MeowMeowPus
siesHaveMore FunMeowMeowMeo
wPussiesHaveMo reFunMeowMeowMeo
wPussiesHaveMor eFunMeowMeowMeowP
ussiesHaveMoreFu nMeowMeowMeowPussi
esHaveMoreFunMeo wMeowMeowPussiesHav
eMoreFunMeowMeowM eowPussiesHaveMor
eFunMeowMeowMeowP ussiesHaveMoreFunM
eowMeowMeowPussie sHaveMoreFunMeowMe owMeowPus
siesHaveM oreFunMeowMeowMe owPussiesHaveMore FunMeowMeowMe
owPussiesHave MoreFunMeowMeowM eowPussiesHaveM oreFunMeowMeowM
eowPussiesHaveM oreFunMeowMeow MeowPussiesHa veMoreFunMeowMeow
MeowPussiesHave MoreFunMeow MeowMeow PussiesHaveMoreFun
MeowMeowMeowPussi esHa veMoreFunMeowMeowMe
owPussiesHaveMoreF unMeowMeowM eowPussiesHaveMoreFu
nMeowMeowMeowPussie sHaveMoreFunMe owMeowMeowPussiesHav
eMoreFunMeowMeowMeo wPussiesHaveMoreFu nMeowMeowMeowPussie
sHaveMoreFunMeowMeo wMeowPussiesHaveMoreFu nMeowMeowMeowPussi
esHaveMoreFunMeowM eowMeowPussiesHaveMoreFu nMeowMeowMeowPuss
iesHaveMoreFunMe owMeowMeowPussiesHaveMoreFu nMeowMeowMeowP
ussiesHaveMor eFunMeowMeowMeowPussiesHaveMore FunMeowMeow
MeowPussi esHaveMoreFunMeowMeowMeowPussiesHave MoreF
unMe owMeowM eowPuss
iesHave MoreF unMeowMeowM
eowPussies Ha veMoreFunMeo
wMeowMeowP us si esHaveMoreFu
nMeowMeowM eow Pus siesHaveMore
FunMeowMeo wMeow Pussi esHaveMoreFu
nMeowMeow MeowPu ssiesH aveMoreFun
Meow MeowMeow Pussie
sHaveMoreFunMeowMeowMeowPussiesHaveM
oreFunMeowMeowMeowPussiesHaveMo
reFunMeowMeowMeowPussies
 
D

Dave Vandervies

Bradley Bungmunch said:
extern int a; /* an allusion to a - it tells the compiler to look
elsewhere for the definition - that's what you'd expect in a header
file *./

Note that that "elsewhere" might be later in the file (but, for a header,
shouldn't be).

int a; /* a tentative definition or an allusion - it's up to the
compiler to decide on the basis of what's elsewhere in the source file
*/

The "what's elsewhere in the source file" (translation unit, to be
precise) here is fairly straightforward: If there's no "true" definition
(one that actually allocates storage), this becomes one, otherwise
it doesn't.

int a=0; /* a real definition */


ANSI, K&R, and Unix all have different strategies for resolving
tentative definitions, allusions, and real declarations.

C requires that there be at most one "true" definition for each
identifier; having more than one in the same translation unit is
a constraint violation, and having more than one across different
translation units invokes undefined behavior.

Some implementations handle this particular type of undefined behavior
by reporting an error at link time; others silently ignore multiple
definitions and treat them as simply references to the same object (which
makes things work as expected if they're the same type, and introduces
Interesting errors otherwise); others can have more creative ways of
dealing with this.



[snip 40 lines]

Isn't alt.fan.warlord the appropriate newsgroup to crosspost to with
oversized .sigs?


dave
 
O

Old Wolf

Jack Klein said:
int a;

...without either the 'static' or 'extern' keywords at file scope, the
documentation is just plain wrong, and nothing has changed in
different versions of the C standard in this regard.

I'm not sure what you mean by "plain wrong". The rest of
your message explains how it is a tentative definition
(which is surely a correct usage). Of course it is wrong
to have 2 different objects with external linkage but the same
name.

I use this in my code sometimes:
STATIC int a;
the point being that if the object has internal linkage then
it doesn't show up in the map file and I don't know its address
so I can't inspect it in the (non-integrated) debugger.
So I can define STATIC as nothing while debugging, and then
define it as 'static' for the release version.
Of course I attempt to choose more unique names than 'a'.
2. There is no external definition, that is file scope declaration
with an initializer. In this case, at the end of the translation
unit, the compiler will act as though an external definition with an
initializer of 0 existed.

Unfortunately I've encountered many (non-standard of course)
embedded compilers that don't initialize the variable to 0.
Does this match your experience?
(I'm now in the habit of specifically initializing all my
file-scope variables, then the linker puts them in a different
section and they get initialized correctly).
 
M

Mabden

Old Wolf said:
Of course I attempt to choose more unique names than 'a'.

But..., doesn't that make your code easier to understand?
(I'm now in the habit of specifically initializing all my
file-scope variables, then the linker puts them in a different
section and they get initialized correctly).

But..., don't you lose the "Surprise!" factor?

It all sounds very planned out and boring...
 
F

Flash Gordon

int a;

...without either the 'static' or 'extern' keywords at file scope,
the documentation is just plain wrong, and nothing has changed in
different versions of the C standard in this regard.

I'm not sure what you mean by "plain wrong". The rest of
your message explains how it is a tentative definition
(which is surely a correct usage). Of course it is wrong
to have 2 different objects with external linkage but the same
name.

I use this in my code sometimes:
STATIC int a;
the point being that if the object has internal linkage then
it doesn't show up in the map file and I don't know its address
so I can't inspect it in the (non-integrated) debugger.
So I can define STATIC as nothing while debugging, and then
define it as 'static' for the release version.
Of course I attempt to choose more unique names than 'a'.[/QUOTE]

You need a better debugger. Most of the debuggers I've used with In
Circuit Emulators and simulators could cope with static and local
variable. Of course, you probably don't have any choice in debuggers :-(
Unfortunately I've encountered many (non-standard of course)
embedded compilers that don't initialize the variable to 0.
Does this match your experience?
(I'm now in the habit of specifically initializing all my
file-scope variables, then the linker puts them in a different
section and they get initialized correctly).

I've had this problem as well. My solution was to reset all memory to
all bits zero during a RAM test that was done at power up in the
startup code (i.e. as part of initialising the C environment).
 

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
473,744
Messages
2,569,484
Members
44,905
Latest member
Kristy_Poole

Latest Threads

Top