extern

D

DevarajA

Can anyone explain me what extern is used for? I thought it was used to
declare variables definited in other files, but i can do that also
without extern.

/*file a.c*/
int a=5;
int main()
{
f();
}

/*file b.c*/
int a;
void f()
{
printf("%d\n",a); /*it prints 5*/
}


Another thing, what happens if i declare a function like this: extern
int fn(void) ?
 
A

ade ishs

DevarajA said:
Can anyone explain me what extern is used for? I thought it was used to
declare variables definited in other files, but i can do that also
without extern.

/*file a.c*/
int a=5;
int main()
{
f();
}

/*file b.c*/
int a;
void f()
{
printf("%d\n",a); /*it prints 5*/
}


Another thing, what happens if i declare a function like this: extern
int fn(void) ?

<quote>
If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if it
were declared with the storage-class specifier extern . If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
</quote>
 
J

Jack Klein

Can anyone explain me what extern is used for? I thought it was used to
declare variables definited in other files, but i can do that also
without extern.

/*file a.c*/
int a=5;
int main()
{
f();
}

/*file b.c*/
int a;
void f()
{
printf("%d\n",a); /*it prints 5*/
}

File b.c has undefined behavior, calling the variadic function
printf() without a prototype in scope, but let's skip that for the
moment.

If you compile these two source files and combine them into a single
executable, you produce undefined behavior. One consequence of
undefined behavior is seeming to work like you expect it to. On other
compiler/linker combinations, you might well get an error from the
linker and no executable produced.

For every function or object with external linkage in a C program
there must be:

1. Either zero or one external definitions of the function or object,
if it is not actually referenced in the program.

2. Exactly one external definition of the function or object, if it
is actually referenced in the program.
Another thing, what happens if i declare a function like this: extern
int fn(void) ?

The extern keyword is redundant on function definitions, declarations,
and prototypes. They have external linkage by default, which is
changed to internal linkage by the use of the static keyword.
 
M

Me

DevarajA said:
Can anyone explain me what extern is used for? I thought it was used to
declare variables definited in other files, but i can do that also
without extern.

I'd *highly* suggest you use the extern keyword when declaring external
variables as opposed to just using:

int a;

because this looks like you're defining a global variable that gets
zero initialized as opposed to declaring a global variable defined in
another translation unit
/*file a.c*/
int a=5;
int main()
{
f();
}

/*file b.c*/
int a;
void f()
{
printf("%d\n",a); /*it prints 5*/
}

You can also do this:

void f()
{
extern int a;
printf("%d\n",a); /*it prints 5*/
}

Without introducing a symbol to the entire file of b.c
Another thing, what happens if i declare a function like this: extern
int fn(void) ?

Same thing that happens when you declare it without the extern.
 
M

Me

Me said:
I'd *highly* suggest you use the extern keyword when declaring external
variables as opposed to just using:

int a;

because this looks like you're defining a global variable that gets
zero initialized as opposed to declaring a global variable defined in
another translation unit

Ok, I'm talking crap here based on information I vaguely remember from
something I read a long time ago (it probably had something to do with
an ancient unix compiler). What you're doing in b.c is called a
tentative definition:

6.9.2/2 "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."

So as you can see, Jack Klein's answer was right about undefined
behavior occuring if you link these two files together because in b.c,
the compiler acts as if you have:

int a = 0;

at the very bottom.
 
D

DevarajA

Me ha scritto:
Ok, I'm talking crap here based on information I vaguely remember from
something I read a long time ago (it probably had something to do with
an ancient unix compiler). What you're doing in b.c is called a
tentative definition:

6.9.2/2 "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."

So as you can see, Jack Klein's answer was right about undefined
behavior occuring if you link these two files together because in b.c,
the compiler acts as if you have:

So if in file b.c i had declared extern int a it would just have
looked for an int a in another translation unit?
 
M

Mark McIntyre

Can anyone explain me what extern is used for?

For non-function type things, declaring objects whose definition is
elsewhere.
I thought it was used to
declare variables definited in other files, but i can do that also
without extern

Sure - at file scope, an object with no storage class is by default
extern. IMHO however its bad practice not to use extern, as its a
good signal to the maintenance crew that they need to look elsewhere
for the actual definition of 'a';
 
F

Flash Gordon

Mark said:
For non-function type things, declaring objects whose definition is
elsewhere.
Yes.


Sure - at file scope, an object with no storage class is by default
extern.

Wrong.

A function declaration without "static" is extern by default, but that
is not true for objects. For objects it is a "tentative declaration" NOT
an extern, although it has external linkage (i.e. other translation
units can access it). If nothing else is seen by the end of the
translation unit then it is as if there was a declaration with a 0
initialiser at the end of the translation unit.

To quote from n1124:
" 6.9.2 External object definitions Semantics
1 If the declaration of an identifier for an object has file scope
and an initializer, the declaration is an external definition for
the identifier.
2 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.
> IMHO however its bad practice not to use extern, as its a
good signal to the maintenance crew that they need to look elsewhere
for the actual definition of 'a';

It is worse than bad practice because otherwise you invoke undefined
behaviour.
 
M

Mark McIntyre

If you compile these two source files and combine them into a single
executable, you produce undefined behavior.

You sure? The second behaves exactly as if it had been declared
extern int a;
For every function or object with external linkage in a C program
there must be:

1. Either zero or one external definitions of the function or object,
if it is not actually referenced in the program.

2. Exactly one external definition of the function or object, if it
is actually referenced in the program.

This is true. However the 2nd is a declaration, not a definition.
 
L

Lawrence Kirby

You sure? The second behaves exactly as if it had been declared
extern int a;

Both have identical (external) linkage but their behaviour in terms of
whether they create a definition is different.
This is true. However the 2nd is a declaration, not a definition.

extern int a;

is just a declaration.

int a;

is a tentative definition (assuming file scope). Its presence ensures that
there will be a definition of a by the end of the translation unit of b.c.
As such both a.c and b.c contain a definition of a so linking them
produces undefined behaviour.

It is called a tentative definition because it allows other tentative
definitions and a full definition in the same translation unit, e.g.

int a;
int a;
int a = 1;

is valid.

Lawrence
 
D

DevarajA

Lawrence Kirby ha scritto:
Both have identical (external) linkage but their behaviour in terms of
whether they create a definition is different.




extern int a;

is just a declaration.

int a;

is a tentative definition (assuming file scope). Its presence ensures that
there will be a definition of a by the end of the translation unit of b.c.
As such both a.c and b.c contain a definition of a so linking them
produces undefined behaviour.

/*file a.c*/
int var2;
int main()
{
var2=99;
return 0;
}

I compiled into an object file (on linux) with:
$ gcc a.c -c -o a.obj
and then i printed it's symbol table with:
$ nm a.obj
This is the output:

00000000 T main
00000004 C var2

where "C" means "The symbol is common. Common symbols are uninitialized
data. When linking, multiple common symbols may appear with the same
name. If the symbol is defined anywhere, the common symbols are treated
as undefined references." (from nm man page)
 
C

Christian Kandeler

DevarajA said:
/*file a.c*/
int var2;
int main()
{
var2=99;
return 0;
}

The second var2 does not have the same scope as the first one, which makes
this example totally irrelevant to the topic of this thread.


Christian
 
D

DevarajA

Christian Kandeler ha scritto:
DevarajA wrote:




The second var2 does not have the same scope as the first one, which makes
this example totally irrelevant to the topic of this thread.

There's not a second var2. I've just assigned to it
 
C

Chris Torek

I compiled into an object file (on linux) with:
$ gcc a.c -c -o a.obj
and then i printed it's symbol table with:
$ nm a.obj
This is the output:

00000000 T main
00000004 C var2

where "C" means "The symbol is common. ...

The so-called "common model", in which var2 uses this "common
symbol" trick, is *optional*: C compilers are not required to
implement one. They may instead use a "def/ref model".

If your C compiler used a def/ref model, the "nm" output for the
above would give var2 the "D" type. Changing the declaration
for var2 to "extern int var2" would give it the "U" type.

C compilers on Unix-like systems never use the def/ref model,
because there are gigabytes of Unix-like-system "freeware" source
code that *require* common-model. C compilers on some other systems
*do* use def/ref, and that code fails to compile on them. (C++
compilers also do use def/ref, even on Unix-like systems.)
 
O

Old Wolf

Flash said:
Wrong.

A function declaration without "static" is extern by default, but that
is not true for objects. For objects it is a "tentative declaration" NOT
an extern, although it has external linkage (i.e. other translation
units can access it). If nothing else is seen by the end of the
translation unit then it is as if there was a declaration with a 0
initialiser at the end of the translation unit.

Firstly, it is /tentative definition/, not declaration.

Also, Mark McIntyre was taking about objects.
The tentative definition in question has external linkage.
The object it identifies must also have external linkage --
whether it is later explicitly declared or not.

Mark McIntyre's comment seems correct; I don't understand the
distinction you draw between an object being "an extern",
vs. "having external linkage".
 
F

Flash Gordon

Chris said:
The so-called "common model", in which var2 uses this "common
symbol" trick, is *optional*: C compilers are not required to
implement one. They may instead use a "def/ref model".

If your C compiler used a def/ref model, the "nm" output for the
above would give var2 the "D" type. Changing the declaration
for var2 to "extern int var2" would give it the "U" type.

C compilers on Unix-like systems never use the def/ref model,

Not true, Chris. If you give gcc the correct command line options on a
Unixlike implementation (Linux) it will not use the common model and
*will* generate an error on linking if a variable is declared twice even
with neither declaration specifying an initialiser.
because there are gigabytes of Unix-like-system "freeware" source
code that *require* common-model. C compilers on some other systems
*do* use def/ref, and that code fails to compile on them.

That I can believe, since gcc probably has the same option on non-unix
like systems ;-)
> (C++
compilers also do use def/ref, even on Unix-like systems.)

That I can't comment on.
 
C

Chris Torek

Not true, Chris. If you give gcc the correct command line options on a
Unixlike implementation (Linux) it will not use the common model and
*will* generate an error on linking if a variable is declared twice even
with neither declaration specifying an initialiser.

OK, make that "never use def/ref by default." :)

The (ancient, way-before-C89) C compiler that really annoyed me
was Whitesmiths C for the Z80, which treated:

int a;

and

extern int a;

as meaning exactly the same thing: "a" was "ref"d but not "def"d.
You *had* to write:

int a = 0;

to get the variable defined. During the winter holiday between
1981 and 1982, I did a consulting job, porting a Votrax text-to-speech
program from PL/M to C, using this compiler. I spent about a day
trying to figure out why some variables were undefined, and others
were defined, when they were all carefully defined exactly once,
and "extern"ed everywhere else. It turned out Whitesmiths C did
not even implement the K&R White-book language.

(I ended up creating a source file consisting of:

int switch_a = 0;
char *option_b = NULL;

and so on, for all the variables that were otherwise uninitialized.)

(The library also lacked most of the usual functions, such as
printf(). Fortunately printf() was not a lot of use in this
particular freestanding system, since the point was to speak for
a blind programmer, not print on a screen.)
 
M

Mark McIntyre

(of two files with int a; in them)
Both have identical (external) linkage but their behaviour in terms of
whether they create a definition is different.

As such both a.c and b.c contain a definition of a so linking them
produces undefined behaviour.

Really? The standard makes it pretty clear that in the absence of a
storage class specifier, a file-scope object is considered to be
extern. And FWIW I can't recall a compiler that behaves otherwise than
to consider two such declarations to be synonyms. I confess, my
initial thought was the same as yours, but closer reading of the
standard deconvinced me. Can you point me to the actual section that
confirms your view?
 
C

Chris Torek

... both a.c and b.c contain a definition of a so linking them
produces undefined behaviour.
[/QUOTE]

Really? The standard makes it pretty clear that in the absence of a
storage class specifier, a file-scope object is considered to be
extern.

You are mixing up "linkage" -- which is indeed external -- with
"definition-ness". The extern keyword usually gives you external
linkage, and usually inhibits definitions. Without the keyword,
you still get external linkage, but the definition is not inhibited:

% grep var a.c b.c
a.c:int var;
b.c:extern int var;

Both have external linkage, but the "extern" in b.c inhibits
the definition, so that B.OBJ will contain a reference (in
compilers that use def/ref linkers).

Note that the "extern" keyword is pretty weak. If we modify b.c
to read, e.g.:

% grep var /dev/null b.c
b.c:static int var;
b.c:extern int var;

then the "var" in b.c has internal linkage (only), or if we modify
it to say "extern int var = 3;", it will be a definition (with
value 3), which will conflict with the definition (with value 0)
in A.OBJ using the system with the def/ref-model compiler. (Systems
that use "common model" and thus give the symbol "var" the type
"common block of size sizeof(int)" will see the Fortran COMMON
block -- this is where the name "common model" comes from -- in
a.o, and the data definition in b.o, and discard the COMMON-block
definition in favor of the data-definition, so again you will see
no conflict.)
 
N

Netocrat

Mark said:
(of two files with int a; in them)

The same was my understanding until this thread, so perhaps I can
explain it knowing where you're coming from, because actually it
behaves as if it had been declared extern int a = 0;
Really? The standard makes it pretty clear that in the absence of a
storage class specifier, a file-scope object is considered to be
extern.

You are probably referring to 6.2.2#5. As Chris Torek points out, this
section specifies that the extern keyword gives the object external
linkage. Aside from linkage, there are two other relevant contexts in
which the word "external" can be applied: to a declaration and to a
definition.
And FWIW I can't recall a compiler that behaves otherwise than
to consider two such declarations to be synonyms. I confess, my
initial thought was the same as yours, but closer reading of the
standard deconvinced me. Can you point me to the actual section that
confirms your view?

You seem to already know the part of the standard requiring that int a;
is treated as extern int a;

6.2.2#5
....
If the declaration of an identifier for
an object has file scope and no storage-class specifier, its
linkage is external.

Below an external declaration is defined as a file-scope declaration,
where it is also clarified that an initialiser turns a declaration into
a definition:

6.9#4
As discussed in 5.1.1.1, the unit of program text after
preprocessing is a translation unit, which consists of a
sequence of external declarations. These are described as
``external'' because they appear outside any function (and
hence have file scope). As discussed in 6.7, a declaration
that also causes storage to be reserved for an object or a
function named by the identifier is a definition.

Below we find out that int a; becomes int a = 0; by end of file in the
absence of other definitions. i.e. 6.2.2#5, 6.9#4 and 6.9.2#2 require
that our external declaration int a; by file end becomes the external
definition with external linkage: extern int a = 0.

6.9.2#2
[#2] 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.

Below we find that a program shall only have one external definition
for each identifier that is actually used. Given that our two files
each contain an identical variable declaration that ultimately becomes
an external definition, this constraint is violated (unless the
variable is not actually used).

6.9#5
An external definition is an external declaration that
is also a definition of a function or an object. If an
identifier declared with external linkage is used in an
expression (other than as part of the operand of a sizeof
operator), somewhere in the entire program there shall be
exactly one external definition for the identifier;
otherwise, there shall be no more than one.127)
____________________

127Thus, if an identifier declared with external linkage is
not used in an expression, there need be no external
definition for it.

Quite a chain of reasoning for the simple conclusion: we must use
extern for one of the declarations.
 

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

No members online now.

Forum statistics

Threads
474,470
Messages
2,571,809
Members
48,797
Latest member
PeterSimpson
Top