By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
429,480 Members | 755 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 429,480 IT Pros & Developers. It's quick & easy.

Defining variable in C header file related doubt

P: n/a
I saw a program source code in which a variable is defined in a header
file and that header file is included in 2 different C files.When i
compile and link the files no error is being thrown.How is this
possible.I thought it will throw "Variable redefinition Error". Giving
the source code for reference.Please help me out on this...

a.h
-----
int g;
void fun(void);

a.c
-----
#include "a.h"
void main()
{
g = 50;
printf("%d\n",g);
fun();
printf("%d\n",g);
}

b.c
----
#include "a.h"
void fun(void)
{
g = 120;
}

Output is 50...120

Regards
Manu
Jun 27 '08 #1
Share this Question
Share on Google+
11 Replies


P: n/a
whirlwindkevin said:
I saw a program source code in which a variable is defined in a header
file and that header file is included in 2 different C files.
And it didn't compile, obviously.
When i
compile and link the files no error is being thrown.
Then you didn't see what you thought you saw.
How is this
possible.I thought it will throw "Variable redefinition Error". Giving
the source code for reference.Please help me out on this...

a.h
-----
int g;
This is not *exactly* a definition. It's a "tentative definition", and it's
one of the silliest ideas in C - a silly feature of the language, and
silly of the programmer to exploit the feature.

Some terms:
A *declaration* is you telling the compiler "see this identifier? When I
use it, I'm talking about an object (or function) of such-and-such a type,
and just trust me that this object exists, okay?" On that understanding, a
compiler can go ahead and compile code that can interact even with objects
or functions that it can't see right now (much as a carpenter can make a
letterbox in a door even without seeing the actual letters that will drop
through it, provided you tell him how big the letters will be). But if you
lie to the compiler, you'll pay later.

A *definition* is you telling the compiler "make me an object of
such-and-such a type" (or a "function that does THIS"). If a declaration
is a promise, then a definition is a way of honouring that promise. A
definition *is* a declaration (because, when you create an object, that's
as good a way as any of informing the compiler that the object exists),
but declarations need not be definitions.

A "tentative definition" is you telling the compiler "it's my intent to
create an object of this type, but I'm not really sure whether this is the
right place to do it". The Standard says:

"A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or with
the storage-class specifier static , constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains no
external definition for that identifier, then the behavior is exactly
as if the translation unit contains a file scope declaration of that
identifier, with the composite type as of the end of the translation
unit, with an initializer equal to 0."

Best advice? Avoid like the plague. Instead, if you must use file scope
object identifiers, do it this way:

1) in exactly one header that can be included by all relevant sources,
write a declaration, such as:

extern int IfYouMustDoThisDamnSillyThing;

2) in the same header, define a sensible initial value for the object:

#define DO_IT_LIKE_THIS 42

3) include that header in all relevant sources;

4) in exactly one source, write a definition at file scope, such as:

int IfYouMustDoThisDamnSillyThing = DO_IT_LIKE_THIS;

void main()
The main function returns int. If you return anything else from main,
you're breaking the rules of C, and C is released from any obligation to
be predictable.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #2

P: n/a
On Jun 9, 12:27 pm, Richard Heathfield <r...@see.sig.invalidwrote:
whirlwindkevin said:
I saw a program source code in which a variable is defined in a header
file and that header file is included in 2 different C files.

And it didn't compile, obviously.
When i
compile and link the files no error is being thrown.

Then you didn't see what you thought you saw.
How is this
possible.I thought it will throw "Variable redefinition Error". Giving
the source code for reference.Please help me out on this...
a.h
-----
int g;

This is not *exactly* a definition. It's a "tentative definition", and it's
one of the silliest ideas in C - a silly feature of the language, and
silly of the programmer to exploit the feature.

Some terms:
A *declaration* is you telling the compiler "see this identifier? When I
use it, I'm talking about an object (or function) of such-and-such a type,
and just trust me that this object exists, okay?" On that understanding, a
compiler can go ahead and compile code that can interact even with objects
or functions that it can't see right now (much as a carpenter can make a
letterbox in a door even without seeing the actual letters that will drop
through it, provided you tell him how big the letters will be). But if you
lie to the compiler, you'll pay later.

A *definition* is you telling the compiler "make me an object of
such-and-such a type" (or a "function that does THIS"). If a declaration
is a promise, then a definition is a way of honouring that promise. A
definition *is* a declaration (because, when you create an object, that's
as good a way as any of informing the compiler that the object exists),
but declarations need not be definitions.

A "tentative definition" is you telling the compiler "it's my intent to
create an object of this type, but I'm not really sure whether this is the
right place to do it". The Standard says:

"A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or with
the storage-class specifier static , constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains no
external definition for that identifier, then the behavior is exactly
as if the translation unit contains a file scope declaration of that
identifier, with the composite type as of the end of the translation
unit, with an initializer equal to 0."

Best advice? Avoid like the plague. Instead, if you must use file scope
object identifiers, do it this way:

1) in exactly one header that can be included by all relevant sources,
write a declaration, such as:

extern int IfYouMustDoThisDamnSillyThing;

2) in the same header, define a sensible initial value for the object:

#define DO_IT_LIKE_THIS 42

3) include that header in all relevant sources;

4) in exactly one source, write a definition at file scope, such as:

int IfYouMustDoThisDamnSillyThing = DO_IT_LIKE_THIS;
void main()

The main function returns int. If you return anything else from main,
you're breaking the rules of C, and C is released from any obligation to
be predictable.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Many Thanks Richard for replying...
Still i have a doubt related to definition of the variable.Can you
please tell where variable g (variable in the above program) is
defined (space is allocated for the variable)? Is it in a.c or is it
in b.c?
Jun 27 '08 #3

P: n/a
whirlwindkevin said:

<snip>
Many Thanks Richard for replying...
Still i have a doubt related to definition of the variable.Can you
please tell where variable g (variable in the above program) is
defined (space is allocated for the variable)? Is it in a.c or is it
in b.c?
No, not really. That's partly why it's such a silly idea. Again, I
recommend that you avoid tentative definitions.

About the most that can be said is that the compiler, having seen a
tentative definition, can at least treat it like a declaration - and one
or other of the tentative definitions is eventually treated as if it were
a definition.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #4

P: n/a
In article <2d**********************************@25g2000hsx.g ooglegroups.com>
whirlwindkevin <ma*******@gmail.comwrote:

[regarding two separate .c files, both with "int g;" with no
initializer for either one, that are compiled separately and
then linked]
>whirlwindkevin said:
>>I saw a program source code in which a variable is defined in a header
file and that header file is included in 2 different C files.
>On Jun 9, 12:27 pm, Richard Heathfield <r...@see.sig.invalidwrote:
>And it didn't compile, obviously.
Well, actually, it did (for him). But as you note:
>>int g;

This is not *exactly* a definition. It's a "tentative definition", and it's
one of the silliest ideas in C - a silly feature of the language, and
silly of the programmer to exploit the feature.
Tentative definitions are actually useful in a few corner cases,
such as creating a circularly linked list at compile time that
has several elements:

struct foolist {
struct foolist *next, *prev;
... more data here ...
};

static struct foolist foo_head, foo_elem_2, foo_tail;

static struct foo_list foo_head = { &foo_elem_2, &foo_tail, ... };
static struct foo_list foo_elem_2 = { &foo_tail, &foo_head, ... };
static struct foo_list foo_tail = { &foo_head, &foo_elem_2, ... };

In C, you must use tentative definitions to make this work. (For
non-"static" variables, which have external linkage, you can use
"extern" to avoid creating tentative definitions.)
>"A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or with
the storage-class specifier static , constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains no
external definition for that identifier, then the behavior is exactly
as if the translation unit contains a file scope declaration of that
identifier, with the composite type as of the end of the translation
unit, with an initializer equal to 0."
However, as one can see if one has an implementation like the OP's,
this is not quite true:

% cat a.define.c
int x = 0;
% cat b.define.c
int x = 0;
int main(void) { return 0; }
% cc -o define a.define.c b.define.c
/tmp/ccodx0za.o(.data+0x0): multiple definition of `x'
/tmp/ccV8U2Fi.o(.data+0x0): first defined here
% cat a.tent.c
int x;
% cat b.tent.c
int x;
int main(void) { return 0; }
% cc -o tent a.tent.c b.tent.c
%

So, we now have to ask: is this implementation broken? The behavior
differs for tentative definitions and actual (non-tentative)
definitions, despite the above quote from the C standard.

The answer is no, because what the Standard giveth at this point,
the Standard taketh away elsewhere:

K.2 Undefined behavior

[#1] The behavior is undefined in the following circumstances:
[massive snippage]
- An identifier with external linkage is used, but in the
program there does not exist exactly one external definition
for the identifier, or the identifier is not used and there
exist multiple external definitions for the identifier.
(6.7).

In other words, the implementation can do anything it wants if you
define the same identifier twice (or any other number of times than
1 or 0, with "defined 0 times" being OK only for one particular
case).

The OP's implementation, like mine above, uses this "undefined
behavior" license to provide a "feature" of sorts: tentative
definitions are turned into actual definitions, but not at the end
of each translation unit. Instead, the compiler waits until the
last possible moment -- the "link" phase of compilation -- and only
*then* turns all remaining tentative definitions into actual
definitions. In the process, it saves a bit of disk space. This
feature also lets lazy programmers leave out the keyword "extern".
>Many Thanks Richard for replying...
Still i have a doubt related to definition of the variable.Can you
please tell where variable g (variable in the above program) is
defined (space is allocated for the variable)? Is it in a.c or is it
in b.c?
According to the Standard, it is in both. However, your implementation
(like mine) makes use of the undefined behavior to cause it to
happen in *neither*. It happens in a third, "invisible" source
file that your compiler makes up at the last possible moment. (In
my implementation, this is not even an actual file at all, although
some compilers do use an extra file, and even a program called
"collect2", to handle some tricky cases, particularly when mixing
C with other languages. If your linker is smart enough, it can
create a sort of "pretend" file purely in RAM, and avoid the
"collect2" step. This job is a lot easier for pure C programs; it
is only those other langauges that create the need for "collect2".)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: gmail (figure it out) http://web.torek.net/torek/index.html
Jun 27 '08 #5

P: n/a

"Richard Heathfield" <rj*@see.sig.invalidwrote in message
news:fe******************************@bt.com...
whirlwindkevin said:
>I saw a program source code in which a variable is defined in a header
file and that header file is included in 2 different C files.

And it didn't compile, obviously.
>When i
compile and link the files no error is being thrown.

Then you didn't see what you thought you saw.
>How is this
possible.I thought it will throw "Variable redefinition Error". Giving
the source code for reference.Please help me out on this...

a.h
-----
int g;

This is not *exactly* a definition. It's a "tentative definition"
Looks like an ordinary definition to me. What's tentative about it?

The OP's question was why, with int g declared in both files (and apparently
sharing the same space) no error was raised.

--
Bartc
Jun 27 '08 #6

P: n/a
"Bartc" <bc@freeuk.comwrites:
"Richard Heathfield" <rj*@see.sig.invalidwrote in message
news:fe******************************@bt.com...
>whirlwindkevin said:
>>I saw a program source code in which a variable is defined in a header
file and that header file is included in 2 different C files.

And it didn't compile, obviously.
>>When i
compile and link the files no error is being thrown.

Then you didn't see what you thought you saw.
>>How is this
possible.I thought it will throw "Variable redefinition Error". Giving
the source code for reference.Please help me out on this...

a.h
-----
int g;

This is not *exactly* a definition. It's a "tentative definition"

Looks like an ordinary definition to me. What's tentative about it?
You need to look up the meaning of tentative definition. But you are
really (in the real world) quite correct. In normal C language it is a
perfectly normal definition.

However in language lawyreville:

,----
| A tentative definition is any external data declaration that has no
| storage class specifier and no initializer. A tentative definition
| becomes a full definition if the end of the translation unit is reached
| and no definition has appeared with an initializer for the
| identifier. In this situation, the compiler reserves uninitialized space
| for the object defined.
`----

http://publib.boulder.ibm.com/infoce...ative_defn.htm

or

http://tinyurl.com/2fqgx7

In many years of professional programming the issue/word has never come
up for me.
Jun 27 '08 #7

P: n/a
In article <g2**********@registered.motzarella.org>,
Richard <rg****@gmail.comwrote:
>>>a.h
-----
;>>>int g;
>>This is not *exactly* a definition. It's a "tentative definition"
>Looks like an ordinary definition to me. What's tentative about it?
>You need to look up the meaning of tentative definition.
Or he could just have read it, since it was quoted in the article he
replied to.

-- Richard
--
In the selection of the two characters immediately succeeding the numeral 9,
consideration shall be given to their replacement by the graphics 10 and 11 to
facilitate the adoption of the code in the sterling monetary area. (X3.4-1963)
Jun 27 '08 #8

P: n/a
On Mon, 09 Jun 2008 12:12:55 GMT, "Bartc" <bc@freeuk.comwrote in
comp.lang.c:
>
"Richard Heathfield" <rj*@see.sig.invalidwrote in message
news:fe******************************@bt.com...
whirlwindkevin said:
I saw a program source code in which a variable is defined in a header
file and that header file is included in 2 different C files.
And it didn't compile, obviously.
When i
compile and link the files no error is being thrown.
Then you didn't see what you thought you saw.
How is this
possible.I thought it will throw "Variable redefinition Error". Giving
the source code for reference.Please help me out on this...

a.h
-----
int g;
This is not *exactly* a definition. It's a "tentative definition"

Looks like an ordinary definition to me. What's tentative about it?

The OP's question was why, with int g declared in both files (and apparently
sharing the same space) no error was raised.
And the answer is, "C doesn't know or care."

The standard states (C99 6.9 p5):

"An external def1nition is an external declaration that is also a
definition of a function (other than an inline definition) or an
object. If an identif1er declared with external linkage is used in an
expression (other than as part of the operand of a sizeof operator
whose result is an integer constant), somewhere in the entire program
there shall be exactly one external definition for the identifier;
otherwise, there shall be no more than one."

If two translation units that define the same object with external
linkage, "int g" in this case, are combined in the same program, the
rule above is broken. Since the program violates a "shall" clause
outside of a constraints section, the behavior is undefined and no
diagnostic is required.

Some tool sets will complain about this, others will not. The
behavior is undefined either way.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
Jun 27 '08 #9

P: n/a
whirlwindkevin <ma*******@gmail.comwrote:
>
I saw a program source code in which a variable is defined in a header
file and that header file is included in 2 different C files.When i
compile and link the files no error is being thrown.How is this
possible.I thought it will throw "Variable redefinition Error". Giving
the source code for reference.Please help me out on this...
Having multiple definitions results in undefined behavior -- the
implementation is not required to diagnose it, and many (if not most)
implementations will not, particularly if the definitions are compatible
and the variable is not explicitly initialized. The code is still
wrong: the header should have only a declaration of the variable (with
extern) and exactly one source file should have the actual definition.

-- Larry Jones

OK, what's the NEXT amendment say? I know it's in here someplace. -- Calvin
Jun 27 '08 #10

P: n/a
Bartc wrote:
"Richard Heathfield" <rj*@see.sig.invalidwrote in message
news:fe******************************@bt.com...
>whirlwindkevin said:
....
>>int g;
This is not *exactly* a definition. It's a "tentative definition"

Looks like an ordinary definition to me. What's tentative about it?
Other people have told you that it's tentative because the standard
defines it to be tentative, and have cited the relevant clause. However,
they didn't say why the standard chose the word "tentative" for this
purpose.

The reason it is tentative is that this definition of 'g' has
characteristics that can be changed by a following definition in the
same translation unit. If there are no other definitions, then 'g' will
have external linkage and be zero-initialized. However, if a following
declaration were to say:

static int g;

Then 'g' would still be tentative, but would have internal linkage.
Alternatively, if a following declaration were to say:

extern int g;

then 'g' would no longer be tentative; it would definitely have external
linkage. Note: if different declarations specify both internal and
external linkage, then the behavior is undefined. Finally, if as
tentative declaration of 'g' were followed by

int g = 10;

the 'g' would not be zero-initialized; it would be initialized with a
value of 10.
Jun 27 '08 #11

P: n/a
On Jun 10, 7:00 pm, James Kuyper <jameskuy...@verizon.netwrote:
Bartc wrote:
"Richard Heathfield" <r...@see.sig.invalidwrote in message
news:fe******************************@bt.com...
whirlwindkevin said:
...
>int g;
This is not *exactly* a definition. It's a "tentative definition"
Looks like an ordinary definition to me. What's tentative about it?

Other people have told you that it's tentative because the standard
defines it to be tentative, and have cited the relevant clause. However,
they didn't say why the standard chose the word "tentative" for this
purpose.

The reason it is tentative is that this definition of 'g' has
characteristics that can be changed by a following definition in the
same translation unit. If there are no other definitions, then 'g' will
have external linkage and be zero-initialized. However, if a following
declaration were to say:

static int g;

Then 'g' would still be tentative, but would have internal linkage.
Alternatively, if a following declaration were to say:

extern int g;

then 'g' would no longer be tentative; it would definitely have external
linkage. Note: if different declarations specify both internal and
external linkage, then the behavior is undefined. Finally, if as
tentative declaration of 'g' were followed by

int g = 10;

the 'g' would not be zero-initialized; it would be initialized with a
value of 10.
Thanks Guys for the help....
Jun 27 '08 #12

This discussion thread is closed

Replies have been disabled for this discussion.