Doubts about Linkage Rules

F

fctk

source: http://rm-f.net/~orange/devel/specifications/c89-draft.html#3.1.2.2

there are two passages in this paragraph i can't fully understand:

1) "If the declaration of an identifier for an object or a function
contains the storage-class specifier extern , the identifier has the
same linkage as any visible declaration of the identifier with file
scope. If there is no visible declaration with file scope, the
identifier has external linkage."

in particular: "the identifier has the same linkage as /any/ /visible/
declaration of the identifier with file scope"

2) "If, within a translation unit, the same identifier appears with both
internal and external linkage, the behavior is undefined."

i can't imagine an example of an identifier having both internal and
external linkage...
 
D

Diomidis Spinellis

fctk said:
source: http://rm-f.net/~orange/devel/specifications/c89-draft.html#3.1.2.2

there are two passages in this paragraph i can't fully understand:

1) "If the declaration of an identifier for an object or a function
contains the storage-class specifier extern , the identifier has the
same linkage as any visible declaration of the identifier with file
scope. If there is no visible declaration with file scope, the
identifier has external linkage."

in particular: "the identifier has the same linkage as /any/ /visible/
declaration of the identifier with file scope"

It means that the following is a legal declaration of foo with file
linkage scope:

static int foo;
extern int foo;

and this a legal declaration of bar with external linkage scope:

int bar;
extern int bar;

The rationale document for C89 explains how this requirement allows the
implementation of a one-pass compiler that generates intermediate
assembly code.

Note that C99 clarifies the *visible* part of the specification as
follows (6.2.2):

"For an identifier declared with the storage-class specifier extern in a
scope in which a *prior* declaration of that identifier is visible, if
the prior declaration specifies internal or external linkage, the
linkage of the identifier at the later declaration is the same as the
linkage specified at the prior declaration. If no prior declaration is
visible, or if the prior declaration specifies no linkage, then the
identifier has external linkage."
2) "If, within a translation unit, the same identifier appears with both
internal and external linkage, the behavior is undefined."

i can't imagine an example of an identifier having both internal and
external linkage...

This is not allowed:

static int bar;
int bar;
 
L

lawrence.jones

fctk said:
there are two passages in this paragraph i can't fully understand: [...]
in particular: "the identifier has the same linkage as /any/ /visible/
declaration of the identifier with file scope"

Visibility of identifiers is discussed in 6.2.1p2. Consider:

extern int i;
static int i;

The second declaration is not yet visible at the first declaration, so
the first declaration declares i to have external linkage.
i can't imagine an example of an identifier having both internal and
external linkage...

See above. :)

If the declarations were reversed, all would be well since the "static"
declaration would be visible at the "extern" declaration and thus the
"extern" declaration would declare "i" with internal linkage, too.

-Larry Jones

How am I supposed to learn surgery if I can't dissect anything? -- Calvin
 
F

fctk

Diomidis Spinellis ha scritto:
This is not allowed:

static int bar;
int bar;

i can't understand why there is a problem with:

static int bar;
int bar;

let me expand the previous example to something as:

static int bar; /* first declaration of `bar' */

void f1(void) {
bar;
}

int bar; /* second declaration of `bar' */

void f2(void) {
bar;
}

first of all let's highlight the scopes of the two declarations of
`bar'; i will put an /* 1 */ in front of all lines that belongs to the
scope of the first declaration, and an /* 2 */ in front of all lines
that belong to the scope of the second declaration:

static int bar; /* first declaration of `bar' */
/* 1 */
/* 1 */ void f1(void) {
/* 1 */ bar;
/* 1 */ }
/* 1 */
int bar; /* second declaration of `bar' */
/* 2 */
/* 2 */ void f2(void) {
/* 2 */ bar;
/* 2 */ }

both declarations of `bar' have file-scope, becouse they are put outside
of any block and outside of any list of parameter declarations in a
function definition.

please note that, as far as i know, given a certain identifier `foo',
the scope of a declaration of `foo' and the scope of another declaration
of `foo' *can't* overlap. overlapping is possible only for the scopes of
*different* identifiers declarations.

the relevant rules here for the linkage are:

1) If the declaration of an identifier for an object or a function has
file scope and contains the storage-class specifier static, the
identifier has internal linkage.

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

so for rule 1) all instances of identifier `bar' within the scope of the
first declaration of `bar' have internal-linkage, while for rule 2) all
instances of identifier `bar' within the scope of the second declaration
of `bar' have external-linkage:

static int bar; /* first declaration of `bar' */
/* 1 */
/* 1 */ void f1(void) {
/* 1 */ bar; /* this instance has internal-linkage */
/* 1 */ }
/* 1 */
int bar; /* second declaration of `bar' */
/* 2 */
/* 2 */ void f2(void) {
/* 2 */ bar; /* this instance has external-linkage */
/* 2 */ }

so as far as i know there is no instance of some identifier with *both*
internal-linkage and external-linkage.

of course my reasoning is wrong in some points, but i can't understand
where.

sorry for the long message.
 
V

Vladimir S. Oka

fctk said:
Diomidis Spinellis ha scritto:

i can't understand why there is a problem with:

said:
first of all let's highlight the scopes of the two declarations of
`bar'; i will put an /* 1 */ in front of all lines that belongs to the
scope of the first declaration, and an /* 2 */ in front of all lines
that belong to the scope of the second declaration:

static int bar; /* first declaration of `bar' */
/* 1 */
/* 1 */ void f1(void) {
/* 1 */ bar;
/* 1 */ }
/* 1 */
int bar; /* second declaration of `bar' */
/* 2 */
/* 2 */ void f2(void) {
/* 2 */ bar;
/* 2 */ }

<snip>

I think your problem is in not understanding scopes properly. The above
example should read (using your notation):

static int bar; /* first declaration of `bar' */
/* 1 */
/* 1 */ void f1(void) {
/* 1 */ bar;
/* 1 */ }
/* 1 */
/* 1 */ int bar; /* second declaration of `bar' */ /* BANG! */
/* 1 */
/* 1 */ void f2(void) {
/* 1 */ bar;
/* 1 */ }

As file scope spans the whole of the file (hence the name).

Functions `f1()` and `f2()` have inner scopes of their own, where you
can declare `bar` again, but that `bar` then is local to the function,
and masks the file scope one from the line where it's declared till the
closing brace of the function.
 
F

fctk

Vladimir S. Oka ha scritto:
I think your problem is in not understanding scopes properly. The above
example should read (using your notation):

static int bar; /* first declaration of `bar' */
/* 1 */
/* 1 */ void f1(void) {
/* 1 */ bar;
/* 1 */ }
/* 1 */
/* 1 */ int bar; /* second declaration of `bar' */ /* BANG! */
/* 1 */
/* 1 */ void f2(void) {
/* 1 */ bar;
/* 1 */ }

As file scope spans the whole of the file (hence the name).

did you mean perhaps something as:

static int bar; /* first declaration of `bar' */
/* 1 */
/* 1 */ void f1(void) {
/* 1 */ bar;
/* 1 */ }
/* 1 */
/* 1 */ int bar; /* second declaration of `bar' */
/* 1 */ /* 2 */
/* 1 */ /* 2 */ void f2(void) {
/* 1 */ /* 2 */ bar;
/* 1 */ /* 2 */ }

?

with the previous notation i mean: the scope of the first declaration
overlaps with the scope of the second declaration from line 8 to line
11, and the second declaration "masks" the first declaration from line 8
to line 11.
 
V

Vladimir S. Oka

fctk said:
Vladimir S. Oka ha scritto:

did you mean perhaps something as:

static int bar; /* first declaration of `bar' */
/* 1 */
/* 1 */ void f1(void) {
/* 1 */ bar;
/* 1 */ }
/* 1 */
/* 1 */ int bar; /* second declaration of `bar' */
/* 1 */ /* 2 */
/* 1 */ /* 2 */ void f2(void) {
/* 1 */ /* 2 */ bar;
/* 1 */ /* 2 */ }

?

with the previous notation i mean: the scope of the first declaration
overlaps with the scope of the second declaration from line 8 to line
11, and the second declaration "masks" the first declaration from line 8
to line 11.

Yes, but you can't have the above. The second declaration is illegal.
That's why I did not include /* 2 */ in my example (I've added a /*
BANG! */, though).
 
F

fctk

Vladimir S. Oka ha scritto:
Yes, but you can't have the above. The second declaration is illegal.
That's why I did not include /* 2 */ in my example (I've added a /*
BANG! */, though).

ok, now i think i understand why the second instance of `bar' in my
example has both internal and external linkage.

anyway i don't understand why the following piece of code (without f1
and f2 functions) is wrong:

static int bar;
int bar;

the previous gets re-written as:

static int bar; /* first declaration of identifier `bar' */
/* 1 */
/* 1 */ int bar; /* second declaration of identifier `bar' */
/* 1 */ /* 2 */

there is *no* instance of identifier `bar' in the scope of some
declaration. so it is false that there is an instance of `bar' with both
external and internal linkage.

when trying to compile, i get:

error: non-static declaration of 'bar' follows static declaration
error: previous declaration of 'bar' was here

i'm sure there is something else i haven't fully understood yet.
 
V

Vladimir S. Oka

fctk said:
Vladimir S. Oka ha scritto:

ok, now i think i understand why the second instance of `bar' in my
example has both internal and external linkage.

anyway i don't understand why the following piece of code (without f1
and f2 functions) is wrong:

static int bar;
int bar;

the previous gets re-written as:

static int bar; /* first declaration of identifier `bar' */
/* 1 */
/* 1 */ int bar; /* second declaration of identifier `bar' */
/* 1 */ /* 2 */

there is *no* instance of identifier `bar' in the scope of some
declaration. so it is false that there is an instance of `bar' with both
external and internal linkage.

when trying to compile, i get:

error: non-static declaration of 'bar' follows static declaration
error: previous declaration of 'bar' was here

i'm sure there is something else i haven't fully understood yet.

Maybe you should try thinking about this particular example in this
way:

static int bar;

Tells the compiler that `bar` is "visible" only internally to the file
in question.

int bar;

Then tells the compiler that it is "visible" externally as well.

Logically, both can't be true at the same time, hence the error.
 
F

fctk

Vladimir S. Oka ha scritto:
Maybe you should try thinking about this particular example in this
way:

static int bar;

Tells the compiler that `bar` is "visible" only internally to the file
in question.

int bar;

Then tells the compiler that it is "visible" externally as well.

Logically, both can't be true at the same time, hence the error.

mmh... but i think there is another error. `static int bar' and `int
bar' are two *definitions* other than two declarations. they are two
definitions of the *same* object.

it is as if i wrote:

static void f1(void) {}
extern void f1(void) {}

isn't it?
 
V

Vladimir S. Oka

fctk said:
Vladimir S. Oka ha scritto:

mmh... but i think there is another error. `static int bar' and `int
bar' are two *definitions* other than two declarations. they are two
definitions of the *same* object.

it is as if i wrote:

static void f1(void) {}
extern void f1(void) {}

isn't it?

Yes, that too. I was just pointing out the other discrepancy.
 
F

fctk

Diomidis Spinellis ha scritto:
It means that the following is a legal declaration of foo with file
linkage scope:

static int foo;
extern int foo;

[...]

Note that C99 clarifies the *visible* part of the specification as
follows (6.2.2):

"For an identifier declared with the storage-class specifier extern in a
scope in which a *prior* declaration of that identifier is visible, if
the prior declaration specifies internal or external linkage, the
linkage of the identifier at the later declaration is the same as the
linkage specified at the prior declaration. If no prior declaration is
visible, or if the prior declaration specifies no linkage, then the
identifier has external linkage."

sorry but i don't understand.

let me rewrite that example as follows:

static int foo; /* D1 */
/* S1 */
/* S1 */ extern int foo; /* D2 */
/* S1 */ /* S2 */

/* D1 */ : declaration1; first declaration of identifier `foo'
/* D2 */ : declaration2; second declaration of identifier `foo'
/* S1 */ : scope1; scope of the first declaration
/* S2 */ : scope2; scope of the second declaration

i don't understand this passage of the rule: "for an identifier declared
[...] in a scope in which a *prior* declaration of that identifier /is/
/visible/, [...]".

D2 is inside S1. let suppose S1 is "visible" to D2. the problem is D1 is
*not* inside S1, so D2 does not know the existence of D1.

this problem could be resolved by "extending" the scopes in the
following way:

/* S1 */static int foo; /* D1 */
/* S1 */
/* S1 */ /* S2 */ extern int foo; /* D2 */
/* S1 */ /* S2 */

all `foo's would have interal-linkage. (( question: but do the instance
of an identifier which occour in a declaration of that identifier have a
kind of linkage? ))

anyway, this "extension" would contract with this other rule:

"Structure, union, and enumeration tags have scope that begins [...].
Each enumeration constant has scope that begins [...]. Any other
identifier has scope that begins /just/ /after/ the completion of its
declarator."
 
F

Flash Gordon

Vladimir said:
Yes, that too. I was just pointing out the other discrepancy.

Actually no, they are both tentative definitions, where as you example
with functions shows definitions. For example, the following is
completely legal:

static int bar; /* tentative definition */
static int bar; /* tentative definition */
static int bar; /* tentative definition */
static int bar; /* tentative definition */
static int bar = 5; /* definition */

This defines only one object named bar which is of type int and is
initialised to 5.

From section 6.9.2 of n1124.pdf
| 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.

Here is example 1 from the same section:
int i1 = 1; // definition, external linkage
static int i2 = 2; // definition, internal linkage
extern int i3 = 3; // definition, external linkage
int i4; // tentative definition, external linkage
static int i5; // tentative definition, internal linkage
int i1; // valid tentative definition, refers to pre vious
int i2; // 6.2.2 renders undefined, linkage disagreement
int i3; // valid tentative definition, refers to pre vious
int i4; // valid tentative definition, refers to pre vious
int i5; // 6.2.2 renders undefined, linkage disagreement
extern int i1; // refers to pre vious, whose linkage is external
extern int i2; // refers to pre vious, whose linkage is internal
extern int i3; // refers to pre vious, whose linkage is external
extern int i4; // refers to pre vious, whose linkage is external
extern int i5; // refers to pre vious, whose linkage is internal

Note that there are only two problem lines in the above example, delete
(or correct) those two lines and it would be completely legal C99 (if
not for the // style comments it would be legal C89 as well).
 
V

Vladimir S. Oka

Flash said:
Actually no, they are both tentative definitions, where as you example
with functions shows definitions.

Right. I stand corrected on the variable part. Should've been more
careful.

After all, speed /is/ the device of shaitan.
 

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

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top