473,287 Members | 1,574 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,287 software developers and data experts.

Defining variable in C header file related doubt

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
11 2885
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
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
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
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 (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: gmail (figure it out) http://web.torek.net/torek/index.html
Jun 27 '08 #5

"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
"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
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
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
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
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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Senthilraja | last post by:
I have the following program using templates. Someone please let me know the syntax to be used for defining the member functions push, pop etc. as non-inline functions. #include <iostream>...
3
by: Chris Mantoulidis | last post by:
Seperate compilation (that's what it's called, right?) seems to be quite popular, so I decided to get some info about it, and (d'oh) use it... But it's whole structure seems weird to me... ...
9
by: Aguilar, James | last post by:
I know that one can define an essentially unlimited number of classes in a file. And one can declare just as many in a header file. However, the question I have is, should I? Suppose that, to...
1
by: nin234 | last post by:
I tried searching the newgroups for an answer to this question. I found many related topics, but didn't find the exact answer I am looking for. I am implementing a class to aid in the logging...
1
by: Arthur Dent | last post by:
Hello all, sorry for the cross-post, but im not sure which group is best for this question. I am an ASP.NET developer, but am learning PHP/perl for the first time now to make some to changes to...
2
by: Sike | last post by:
Hi everyone, I've been browsing this and a few other related newsgroups trying to get my head around this problem, and so far all the trails seem to go cold, without an acceptable solution being...
2
by: Cliff Martin | last post by:
I want to define several groups of related magic numbers. I am writing a program to parse someone else's formatted data, and they have several fields that could be set to a number of different...
7
by: Roman Mashak | last post by:
Hello, I have a small piece of code, compiled by two 'gcc' and 'borland builder compiler'. The latter one produces warnings: Public symbol '_freq' defined in both module...
2
by: krreks | last post by:
I'm experiencing some (beginner) problems with my header files... I'm writing an message application and want to split my application into multiple files. So far, everything related to bitwise...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: MeoLessi9 | last post by:
I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines"....
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: Aftab Ahmad | last post by:
Hello Experts! I have written a code in MS Access for a cmd called "WhatsApp Message" to open WhatsApp using that very code but the problem is that it gives a popup message everytime I clicked on...
0
by: Aftab Ahmad | last post by:
So, I have written a code for a cmd called "Send WhatsApp Message" to open and send WhatsApp messaage. The code is given below. Dim IE As Object Set IE =...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.