473,545 Members | 2,011 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Specifier extern

Hi,

I've tree questions on the storage class specifier "extern":

1) Code example:
int main( void )
{
int b = -2; // my line 3

if ( a ) {
extern b; // my line 6
b++;
}
return 0;
}

When compiled, gcc issues the linker error:
/tmp/ccGyuXeO.o(.tex t+0x2d): In function `main':
: undefined reference to `b'
collect2: ld returned 1 exit status

I don't understand why in line 14 "b" is not resolved.
According to ISO/IEC 9899:1999 §6.2.2.4 the object "b" declared extern that
is the same scope in which a prior declaration of that identifier
(int b = -2 ) is visible, the linkage of the
identifier of the latar declaraion (extern b) should be the same as the linkage
specified at th prior declaration. Thus, IMHO object "b" in line 3 should
be declared as an internal linkage object same as done in the prior
declaration/defintion in line 6. So, why does the linker process fail?
2) Similar problem, code example:
int b = 2; // line 1
int main( void )
{
if ( a ) {
extern b; //line 5
b++;
}
return 0;
}

In contrast to the last example, integer "b" is not defined globally.
What linkage type is object "b" now? According to ISO/IEC 9899:1999
§6.2.2.4, it should adopt the linkage type of the prior declaration of
the same identifier, namely internal linkage as used in line 1. Right?
3) Paragraphs §6.2.2.4 and §6.2.2.7 in the ISO/IEC 9899:1999 are somehow
conflictive. According to §6.2.2.7, the varying linkage types of "b" in
the code of my 2. question would lead to undefined behaviour. However,
§6.2.2.4 would define "b" in line 5 as internal linkage object (see my 2.
question).

Thank you for your answers.

Regards,
Chris
Jun 1 '06 #1
5 2843
A small correction:

1) Code example:
extern b; // my line 6 Should be:
extern int b; // my line 6

2) Similar problem, code example:
extern b; //line 5


Same problem here, should be:
extern int b;
Jun 1 '06 #2
Christian Christmann wrote:
Hi,

I've tree questions on the storage class specifier "extern":

1) Code example:
int main( void )
{
int b = -2; // my line 3

if ( a ) {
extern int b; // my line 6
b++;
}
return 0;
}

When compiled, gcc issues the linker error:
/tmp/ccGyuXeO.o(.tex t+0x2d): In function `main':
: undefined reference to `b'
collect2: ld returned 1 exit status

I don't understand why in line 14 "b" is not resolved.
**Important note to OP and other clc readers: my responses here are
more of an exercise for myself to see if I have a good grasp of linkage
and scope in C, so if there are any mistakes, please do not hestitate
to correct me.

Note: I changed 'extern b' to 'extern int b'

I believe the compiler. If you just look at the linkage side of things,
then the later declaration of b should assume the linkage of the most
previous declaration of b (internal linkage), but that IMHO isn't the
problem. The problem is the definition of b (the line "int b = -2").
Because it appears inside a function and does not explicitly define a
storage class, it is given storage class auto by default. The later
declaration of b as "extern" is therefore a contradiction - "extern"
and "auto" are both storage class specifiers, but an object is only
allowed to have *one* storage class. I imagine the following scenario:
suppose all objects of storage class auto get stored on a stack, while
objects of storage class extern get stored in program memory, separate
from the stack. If you declare a previously-defined "auto" object as an
"extern" object, it would be like saying the variable was allocated on
the stack, but it's also allocated in program memory somewhere else at
the same time, which of course doesn't make sense and my guess as to
why it ain't allowed :-)

The compiler ultimately assumes that your "extern int b" must be
referring to a different "b" than the one you declare and define in
main(), i.e. one that has storage class extern and external linkage;
the compiler can't find such a variable and complains accordingly.

According to ISO/IEC 9899:1999 §6.2.2.4 the object "b" declared extern that
is the same scope in which a prior declaration of that identifier
(int b = -2 ) is visible, the linkage of the
identifier of the latar declaraion (extern b) should be the same as the linkage
specified at th prior declaration. Thus, IMHO object "b" in line 3 should
be declared as an internal linkage object same as done in the prior
declaration/defintion in line 6. So, why does the linker process fail?
2) Similar problem, code example:
int b = 2; // line 1
int main( void )
{
if ( a ) {
extern int b; //line 5
b++;
}
return 0;
}

In contrast to the last example, integer "b" is not defined globally.
What linkage type is object "b" now? According to ISO/IEC 9899:1999
§6.2.2.4, it should adopt the linkage type of the prior declaration of
the same identifier, namely internal linkage as used in line 1. Right?

Note: Changed "extern b" to "extern int b"

Not quite. First off, in line 1 your "int b" has external linkage: A
variable defined in file-scope and which isn't "static" has external
linkage by default. Now, since "b" is external but you access it within
the same source file, you don't (technically) have to declare it again
on line 5, because "b" would still be in scope inside main(), although
the explicit "extern int b" clarifies the use of "b" -- you know by
looking at it that "b" is defined outside of main(). As an aside, if
you instead left out the "extern" and wrote "int b" on line 5, the
result would be to create an internal auto variable named "b" that is
more visible than the "b" declared on line 1 i.e. variable shadowing.
3) Paragraphs §6.2.2.4 and §6.2.2.7 in the ISO/IEC 9899:1999 are somehow
conflictive. According to §6.2.2.7, the varying linkage types of "b" in
the code of my 2. question would lead to undefined behaviour. However,
§6.2.2.4 would define "b" in line 5 as internal linkage object (see my 2.
question).


Again, in your example, "b" has implicit external linkage - the linkage
type of "b" never changes.

Mike S

Jun 1 '06 #3
>Christian Christmann wrote:
int main( void )
{
int b = -2; // my line 3

if ( a ) {
extern int b; // my line 6
b++;
}
return 0;
}
In article <11************ **********@f6g2 000cwb.googlegr oups.com>
Mike S <mg******@netsc ape.net> wrote:
**Important note to OP and other clc readers: my responses here are
more of an exercise for myself to see if I have a good grasp of linkage
and scope in C, so if there are any mistakes, please do not hestitate
to correct me.
OK, you are missing a couple of things, some small and one fairly large:
Note: I changed 'extern b' to 'extern int b'
(This is good since C99 requires a type-name. In C89 aka C90 it is
OK to leave it out, but I would say "not good style".)
I believe the compiler. If you just look at the linkage side of things,
then the later declaration of b should assume the linkage of the most
previous declaration of b (internal linkage), but that IMHO isn't the
problem.
Actually, the most recent declaration+def inition of "b" (int b = -2)
has *no* linkage.
The problem is the definition of b (the line "int b = -2").
Because it appears inside a function and does not explicitly define a
storage class, it is given storage class auto by default.
This is correct -- but "storage-class" (more precisely, "storage
duration", as specified by a storage-class specifier) is mostly
separate from linkage. There are three possible storage durations
for objects: static, automatic, and allocated. (The lattermost
was missing from C89 but one might as well just assume it was
included, since otherwise malloc and free cannot work. Also, there
are 5 storage class specifier keywords: auto, register, static,
extern, and -- purely for syntactic reasons -- typedef.)

There are also three possible linkages for identifiers: "external",
"internal", and "none". Note the distinction here between "objects",
which have storage duration, and identifiers, which have linkage.
When we deal with ordinary variable names ("b", "foo", whatever)
we generally have both an object and an identifier, though. (I
use weasel-words here to sidestep issues with identifiers for
functions, typedef'ed names, goto labels, etc.)
The later declaration of b as "extern" is therefore a contradiction
- "extern" and "auto" are both storage class specifiers, but an
object is only allowed to have *one* storage class.
This is true; but we can have more than one object with the same
name:

double xyz = 3.1415926535897 932384626433832 79502884;

void f(void) {
int xyz = 42;
...
}

Here we have two different "xyz"s. The outer one, at file scope,
declares and defines an object (of type "double") with static
duration and external linkage. The inner one, at block scope,
declares and defines an object (of type "int") with automatic
duration and no linkage.

One hard and fast requirement is that identifiers for objects
that have automatic duration always have no linkage, and are always
at block scope. However, this does not work in reverse: identifers
that are at block scope can have linkage, and can have other than
automatic duration:

void g(void) {
static int zorg; /* block scope, static duration, no linkage */
extern double evil; /* static duration, external linkage */
...
}

The "extern" keyword is particularly squirrely, because it means
"external linkage unless already visible with internal linkage".
It also has a side effect of suppressing definition-ness, if a
declaration that would be a definition would be a "tentative
definition":

int abc; /* "tentative definition" of abc (an int) */
int def = 4; /* "definite definition" of def */
extern int ghi; /* declaration (and nothing else) of ghi */
extern int jkl = 5; /* "definite definition" of jkl */

At the end of a "translatio n unit", any tentative definitions become
actual definitions, initialized as if with "= {0}".

What this means is that, for identifiers that name objects, there
are *five* properties we have to be concerned about:

- type (int, double, etc.; these are "obvious" and are independent
of the rest of these items so I will now ignore "type")
- scope (file or block)
- linkage (external, internal, or none)
- storage duration (static or automatic)
- definition-ness (yes, "tentative" , or no)

The "interestin g" keywords here -- auto, extern, register, and
static, which are the storage-class specifier keywords excluding
"typedef" -- have various effects on scope, linkage, storage
duration, and definition-ness:

"auto": allowed only in block scope and then has no effect
"register": allowed only in block scope and then has no effect
"static": allowed in both block and file scope; effect
depends on which scope: can change duration or linkage
"extern": allowed in both block and file scope; effect
depends on visible previous declaration(s), if any,
and on whether the definition-ness is already absolute:
can change linkage, duration, and definition-ness

For an identifier naming an object in block scope, "static" gives
it static duration; it continues to have "no linkage". For the
same kind of identifier in file scope, "static" gives it internal
linkage; it already had static duration.

For an identifer naming an object in block scope, "extern" gives
it the same linkage as any previous visible linkage; but if the
only visible name has no linkage, extern gives it external linkage.
If the identifier is in file scope, any previous visible linkage
is by definition either internal or external, so extern just re-uses
that linkage.

If no previous declaration is visible, extern gives the identifier
external linkage (at any scope). The object will have static
duration, and "tentative definition-ness" is suppressed so that a
declaration that does not provide an initial value is just a
declaration, not a declaration-and-tentative-definition.

Thus, we can make up a table, giving the four "interestin g" properties
for identifiers that name objects, and the way the four keywords affect
them, depending on whether they appear in block or file scope. The
last entry is for "if no keyword is used".

+----------------------+-----------+----------+--------------------+
| keyword | duration | linkage | definition? |
+----------------------+-----------+----------+--------------------+
| auto (file scope) | (illegal) | ---- | --- |
| (block scope) | automatic | none | yes |
+----------------------+-----------+----------+--------------------+
| register(file scope) | (illegal) | ---- | --- |
| (block scope) | automatic | none | yes |
+----------------------+-----------+----------+--------------------+
| static (file scope) | static | internal | yes |
| (block scope) | static | none | yes |
+----------------------+-----------+----------+--------------------+
| extern (file scope) | static | varies | suppress tentative |
| (block scope) | static | varies | no (cannot init.) |
+----------------------+-----------+----------+--------------------+
| (none) (file scope) | static | external | tentative or yes |
| (none) (block scope) | automatic | none | yes |
+----------------------+-----------+----------+--------------------+

"Varies" means "external unless currently shown to be internal".
The "currently shown" part is tricky at block scope, since it
depends on whether a previous file-scope declaration has been
obscured by a block-scope declaration for the same identifier.

Note that the "auto" keyword is redundant: it is illegal at file
scope, and at block scope, it does the same thing you would get
if you did not use a storage-class specifier keyword.
The compiler ultimately assumes that your "extern int b" must be
referring to a different "b" than the one you declare and define in
main(), i.e. one that has storage class extern and external linkage;
the compiler can't find such a variable and complains accordingly.
This part is correct.

Now on to the second example...
int b = 2; // line 1
int main( void )
{
if ( a ) {
extern int b; //line 5
b++;
}
return 0;
}

In contrast to the last example, integer "b" is not defined globally.
What linkage type is object "b" now? According to ISO/IEC 9899:1999
§6.2.2.4, it should adopt the linkage type of the prior declaration of
the same identifier, namely internal linkage as used in line 1. Right?

Note: Changed "extern b" to "extern int b"

Not quite. First off, in line 1 your "int b" has external linkage: A
variable defined in file-scope and which isn't "static" has external
linkage by default.


Right. Look in the table above: no keyword, file scope: we get static
duration, external linkage, and "tentative or yes" definition. The
declaration includes an initial value so the "definition " answer is
"yes".

On line 5, we have extern at file scope, so (per the table) we get
static duration, "varies" linkage, and "no" for definition. There
is no initializer (one would be illegal here anyway) and "tentative
definition-ness" is suppressed, so this is purely a declaration.

For a third and fourth example, consider:

static int x = 42; /* declaration 1 (also definition) of x */

int main(void) {
int a = 0;
{
extern int x; /* decl 2: iffy, but legal */
x++;
}
}

The "extern int x" line again refers to this entry:

keyword duration linkage definition?
+----------------------+-----------+----------+--------------------+
| extern (file scope) | static | varies | suppress tentative |
| (block scope) | static | varies | no (cannot init.) |
+----------------------+-----------+----------+--------------------+

It is at block scope so the duration is "static" and definition-ness
is "no", but as before, the linkage is "varies". We must play
compiler and ask "is there a previous x in some visible scope that
has some linkage?" The answer is yes: the previous file-scope
"static int x" is visible, and has internal linkage. So here "x"
gets internal linkage, and this refers to the same "x" as the
"static int x = 42".

If we change "int a = 0;" to "int x = 0;" in main(), however, we get:

static int x = 42; /* decl 1 (also definition) */

int main(void) {
int x = 0; /* decl 2 (also definition) */
{
extern int x; /* decl 3: ERROR */
x++;
}
}

Here the only visible "x" at the "extern int x" line is the
block-scope "x", which has no linkage. Thus, "extern int x" gives
the third declaration of "x" external linkage, in spite of the
first declaration giving it internal linkage. This triggers
undefined behavior (paragraph 7 of section 6.1.2.2 of the C99 draft
I keep handy).
--
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: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Jun 1 '06 #4
Christian Christmann <pl*****@yahoo. de> wrote:

According to ISO/IEC 9899:1999 6.2.2.4 the object "b" declared extern that
is the same scope in which a prior declaration of that identifier
(int b = -2 ) is visible, the linkage of the
identifier of the latar declaraion (extern b) should be the same as the linkage
specified at th prior declaration.
Only if the prior declaration has internal or external linkage. In this
case, the prior declaration is for a block scope identifier without
extern, so it has no linkage (6.2.2p6) and thus the latter declaration
specified external linkage.
In contrast to the last example, integer "b" is now defined globally.
What linkage type is object "b" now? According to ISO/IEC 9899:1999
6.2.2.4, it should adopt the linkage type of the prior declaration of
the same identifier, namely internal linkage as used in line 1. Right?
Almost, the prior declaration actually specified external linkage (it
would only be internal linkage if it were declared static: see 6.2.2p3
and p5).
3) Paragraphs 6.2.2.4 and 6.2.2.7 in the ISO/IEC 9899:1999 are somehow
conflictive.


No, they're not. The rules in p4 cannot create the situation described
in p7 since they result in both declarations having the same linkage or
the first having no linkage and the second having external linkage. The
only way to run afoul of p7 is by explicitly declaring something extern
and then later declaring it static.

-Larry Jones

Sheesh. Who can fathom the feminine mind? -- Calvin
Jun 1 '06 #5

Chris Torek wrote:
Christian Christmann wrote:
int main( void )
{
int b = -2; // my line 3

if ( a ) {
extern int b; // my line 6
b++;
}
return 0;
}
In article <11************ **********@f6g2 000cwb.googlegr oups.com>
Mike S <mg******@netsc ape.net> wrote:
**Important note to OP and other clc readers: my responses here are
more of an exercise for myself to see if I have a good grasp of linkage
and scope in C, so if there are any mistakes, please do not hestitate
to correct me.
OK, you are missing a couple of things, some small and one fairly large:

[snip] I believe the compiler. If you just look at the linkage side of things,
then the later declaration of b should assume the linkage of the most
previous declaration of b (internal linkage), but that IMHO isn't the
problem.


Actually, the most recent declaration+def inition of "b" (int b = -2)
has *no* linkage.


I was pondering that myself after re-reading what I had written.

I think I momentarily confused internal linkage with the incorrent
notion that it meant "a declaration+def inition known only in the
function in which it appears" instead of "a declaration+def initon known
only in the translation unit in which it appears." I accidentally
married the concept of automatic storage with the concept of internal
linkage, the lovechild of which was my mislabeling of "b"s linkage type
;-)

In any event, thanks for the detailed and very informative response.
That definitely makes things clearer. When I get home I think I'll
torture my compiler with whatever strange and unholy combinations of
linkage and storage duration I can cook up, now that I have the proper
ammunition.
[very good break-down of linkage/storage duration/scope rules snipped...]


Mike S

Jun 1 '06 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

10
6142
by: Mark A. Gibbs | last post by:
I have a question about mixing C and C++. In a C++ translation unit, I want to define a function with internal linkage and C calling convention. Here's a sample of what I want to do: // main.cpp // This is defined in a C module extern "C" void fake_qsort(void*, std::size_t, std::size_t, int (*compare)(const void*, const void*));
1
2502
by: ravi_shankar | last post by:
I know java,but I am just beginner in C.I have some confusions regarding extern storage specifier and default storage class specifier for a variable when it has file scope that is ,when it is not defined within any block -- Posted via http://dbforums.com
12
2700
by: G Patel | last post by:
I've seen some code with extern modifiers in front of variables declared inside blocks. Are these purely definitions (no definition) or are they definitions with static duration but external linkage? Not much on this in the FAQ or tutorials.
19
3825
by: ccwork | last post by:
Hi all, I am reading "C: A Reference Manual" 4th ed and I get lost for the "extern". It says that global object without specifying the storage-class specifier will have "extern" as the default storage-class specifier. My (little) C experience tells me that an object with "extern" is to let the linker knows that the object is referencing the...
29
448
by: DevarajA | last post by:
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(); }
17
4909
by: Tapeesh | last post by:
I would like to know what is the expected behaviour of C compilers when an extern decleration is intialized. When the following code is compiled using gcc //File extern.c int arr ; int a ;
7
2170
by: Christian Christmann | last post by:
Hi, I've a a question on the specifier extern. Code example: void func( void ) { extern int e; //...
3
6384
by: coder | last post by:
While reading the page on "Reading C Declarations" <http://www.ericgiguere.com/articles/reading-c-declarations.html> (recommended by Mr. Heathfield at <http://www.cpax.org.uk/prg/portable/c/resources.php>), I came across the following declaration: extern char *const (*goop( char *b ))( int, long ); which is explained as:
5
9574
by: quarkLore | last post by:
As this link points it out one can use extern instead of a function prototype. Are they one and the same in terms of standard, maintainability? Has some one seen an advantage of one over the other? When should one use simple prototype and when should one use an extern? http://www.eskimo.com/~scs/cclass/notes/sx5b.html
0
7475
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7409
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
7921
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
1
7437
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
0
7771
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the...
0
5982
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
1
5343
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
4958
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3465
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...

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.