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

"extern" question?

P: n/a
I have 3 files (see below: a.h, w.c, ww.c). I would like to use a
single x (declared somewhere) which would global to both compilation
units: w.c & ww.c. No matter where I place the "extern" qualifier - it
appears to work: x is shared between w.c and ww.c. Or if I simple
don't use "extern", it works. Why? What is the correct (or simply
preferred) usage?

---John

PSI'm using gcc (GCC) 4.0.2.

/*---------------a.h-----------------*/
#ifndef _A_H
#define _A_H

extern int x;
void g( void );

#endif /* _A_H */

/*---------------w.c-----------------*/
#include <stdio.h>
#include <stdlib.h>
#include "a.h"

int x;

void g( void )
{
x = 12;
fprintf( stderr, "x = %d\n", x );
}

/*---------------ww.c-----------------*/
#include <stdio.h>
#include <stdlib.h>
#include "a.h"

int x;

int main( int argc, char *argv[] )
{
g();
x = 144;
fprintf( stderr, "x = %d\n", x );
g();
fprintf( stderr, "x = %d\n", x );
}

Aug 15 '06 #1
Share this Question
Share on Google+
5 Replies


P: n/a
On 15 Aug 2006 12:27:14 -0700, "jc**********@gmail.com"
<jc**********@gmail.comwrote in comp.lang.c:
I have 3 files (see below: a.h, w.c, ww.c). I would like to use a
single x (declared somewhere) which would global to both compilation
units: w.c & ww.c. No matter where I place the "extern" qualifier - it
appears to work: x is shared between w.c and ww.c. Or if I simple
don't use "extern", it works. Why? What is the correct (or simply
preferred) usage?
The only CORRECT usage is to have one and only definition of the
object (a declaration without the extern keyword, or a declaration
with an initializer with or without the extern keyword) in one
translation unit, and a declaration with the extern keyword and no
initializer in every other translation unit that references the
object.

The preferred usage, is to put the external declaration (with extern,
without initializer) in a header and include that header in all
translation units that reference the object, including the one that
defines it.
PSI'm using gcc (GCC) 4.0.2.

/*---------------a.h-----------------*/
#ifndef _A_H
Here is something else that is not CORRECT. You violate the language
standard when you define identifiers beginning with two underscores,
or an underscore followed by an upper case letter, in your code. All
such identifiers with this pattern are reserved for the implementation
(compiler). Change this.
#define _A_H

extern int x;
void g( void );

#endif /* _A_H */

/*---------------w.c-----------------*/
#include <stdio.h>
#include <stdlib.h>
#include "a.h"

int x;

void g( void )
{
x = 12;
fprintf( stderr, "x = %d\n", x );
}

/*---------------ww.c-----------------*/
#include <stdio.h>
#include <stdlib.h>
#include "a.h"

int x;

int main( int argc, char *argv[] )
{
g();
x = 144;
fprintf( stderr, "x = %d\n", x );
g();
fprintf( stderr, "x = %d\n", x );
}
The C standard is quite specific about external definitions for
objects or functions. For an object or function that appears in an
external declaration but is not referenced by the program, there may
be either zero or one external definition. For an object or function
in an external declaration that is referenced by the program, there
must be exactly one and only one external definition. If a program
violates these conditions, the result is undefined behavior.

In your snippets, you show three different files that each have an
external definition of the int object x. That invokes undefined
behavior, since you have more than one definition. Once you produce
undefined behavior, the C standard no longer knows or cares what
happens, One possible result of undefined behavior is the program
might do what you expected it to do.

--
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.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Aug 15 '06 #2

P: n/a
Ark
Jack Klein wrote:
<snip>
The only CORRECT usage is to have one and only definition of the
object
<snip>
....with the notable exception of tentative definitions.
- Ark
Aug 16 '06 #3

P: n/a
On Tue, 15 Aug 2006 21:48:50 -0400, Ark <ak*****@macroexpressions.com>
wrote in comp.lang.c:
Jack Klein wrote:
<snip>
The only CORRECT usage is to have one and only definition of the
object
<snip>
...with the notable exception of tentative definitions.
- Ark
No, because a tentative definition is not an actual external
definition. 6.9.2 makes this quite clear. An external definition has
an initializer, while a tentative definition does not.

The wording of the standard makes this quite clear:

"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."

So the tentative definition itself is never an actual definition of an
object, but it causes the compiler to act "as if" there were an
external definition, that is one with an initializer of 0.

--
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.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Aug 16 '06 #4

P: n/a

jc**********@gmail.com wrote:
I have 3 files (see below: a.h, w.c, ww.c). I would like to use a
single x (declared somewhere) which would global to both compilation
units: w.c & ww.c. No matter where I place the "extern" qualifier - it
appears to work: x is shared between w.c and ww.c. Or if I simple
don't use "extern", it works. Why? What is the correct (or simply
preferred) usage?

---John

PSI'm using gcc (GCC) 4.0.2.

/*---------------a.h-----------------*/
#ifndef _A_H
#define _A_H

extern int x;
void g( void );

#endif /* _A_H */

/*---------------w.c-----------------*/
#include <stdio.h>
#include <stdlib.h>
#include "a.h"

int x;

void g( void )
{
x = 12;
fprintf( stderr, "x = %d\n", x );
}

/*---------------ww.c-----------------*/
#include <stdio.h>
#include <stdlib.h>
#include "a.h"

int x;

int main( int argc, char *argv[] )
{
g();
x = 144;
fprintf( stderr, "x = %d\n", x );
g();
fprintf( stderr, "x = %d\n", x );
}
Hi,

1. First of all extern is not a qualifier , it is a storage class
specifier. Because in C, type qualifier implies const and volatile.

2. Explicit "extern" declaration is needed only if the object
definition is in another source file, which the compiler cannot resolve
at compile time. They will be resolved only while linking the
module/Translation Unit(TU) containing the definition with the file
containing declaration.

3. If the definition is in the same source file as the
declaration,then, the "extern" keyword for declaration is optional.
Since the header is already included, that means the defintion is
present in this TU. Hence no explicit extern is needed.

Regards,
Sarathy

Aug 16 '06 #5

P: n/a
Ark
Jack Klein wrote:
On Tue, 15 Aug 2006 21:48:50 -0400, Ark <ak*****@macroexpressions.com>
wrote in comp.lang.c:
>Jack Klein wrote:
<snip>
>>The only CORRECT usage is to have one and only definition of the
object
<snip>
...with the notable exception of tentative definitions.
- Ark

No, because a tentative definition is not an actual external
definition. 6.9.2 makes this quite clear. An external definition has
an initializer, while a tentative definition does not.

The wording of the standard makes this quite clear:

"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."

So the tentative definition itself is never an actual definition of an
object, but it causes the compiler to act "as if" there were an
external definition, that is one with an initializer of 0.
What I meant was:

1.
int x; //tentative or not?
The compiler doesn't know until the end of the translation unit.

2.
//four definitions, three of them tentative
int x;
int x;
int x;
int x /*maybe, = 2006, so "as-if" initializer ain't necessarily 0 */;

[I don't think we disagree on anything: I was just picking on "one and
only one". And tentative definitions are very real in that they legalize
(define?) addresses which can be used in looped static initializers like
void *head;
void *tail = &head;
void *head = &tail;
AFAIK, that's what they are for; but maybe there are uses that I don't
know about.
]
Aug 16 '06 #6

This discussion thread is closed

Replies have been disabled for this discussion.