Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

bogosity in linkage concept.

47 views
Skip to first unread message

Kaz Kylheku

unread,
Apr 10, 2014, 2:30:21 PM4/10/14
to
Consider:

"An identifier declared in different scopes or in the same scope more than
once can be made to refer to the same object or function by a process called
linkage. There are three kinds of linkage: external, internal, and none."
[C99, 6.2.2]

How can "none" be a kind of linkage? Consider a sentence like: "There are three
kinds of beer: lagers, ales and none". What? No beer is a kind of beer?

"If an identifier has no linkage, there shall be no more than one declaration
of the identifier (in a declarator or type specifier) with the same scope and
in the same name space, except for tags as specified in 6.7.2.3."
[C99, 6.7]

So, "no linkage" is in fact a kind of linkage, just with a poor name.

Consider the situation

{ int x; int x; }

which violates a constraint. But the diagnosis of the constraint violation
requires x to be deemed as having linkage. The diagnosis logically
depends on:

1. An identifier is being declared more than once in the same scope.
2. That identifier refers to the same object or function.

and these requires the "process called linkage".

The process of looking up x in one declaration to see whether it was already
mentioned by another declaration is linkage!

x has linkage, and it's just not allowed. So "no linkage" doesn't mean
"lack of linkage" but something like "disallowed linkage".

But the exception for struct and union tags shows that in fact some forms of
"no linkage" are allowed. So the process by which two struct declarations
arefer to the same struct, is evidently linkage of type "none". W00T?

--

It would be cleaner to have a model roughly like this, with only one
kind of linkage:

- There is only one kind of linkage (same as what is now called "external
linkage").

- Linkage is what allows multiple declarations of a name (which is attributed
as having linkage) to refer to the same *external* definition anywhere in the
program, regardless of in which translation units the definition and
declarations are found. Linkage comes into play, during the process of
linking when translated translation units are combined to form a program.
Situations in which multiple declarations of a symbol refer to the same
entity, but that symbol is not attributed with linkage, are not instances
of the linkage process.

- Functions declared with the static keyword, and objects in any scope
declared with that keyword, do not have linkage. (There is no "internal
linkage"). A file scope static object is the same kind of thing as a block
scope static object in every regard, except that it has file scope, and so
can be referenced by more than one function in that translation unit.

- For some kinds of names, the file scope can contain more than one declaration
for the same name (but not more than one non-tentative definition); these
declarations refer to the same entity (by a translation-time symbolic
identification process which is not a form of linkage, which these
identifiers do not have!)

- A block scope can contain more than one declaration of the same struct
or union tag, which refer to the same struct or union by a symbolic
identification process which is not linkage.

- In the same block scope, a name which has no linkage, and is not a
struct/union tag can be declared only once.

Tim Rentsch

unread,
Apr 10, 2014, 11:08:18 PM4/10/14
to
Kaz Kylheku <k...@kylheku.com> writes:

> Consider:
>
> "An identifier declared in different scopes or in the same scope
> more than once can be made to refer to the same object or
> function by a process called linkage. There are three kinds of
> linkage: external, internal, and none." [C99, 6.2.2]
>
> How can "none" be a kind of linkage? [snip elaboration]

Clearly an identifier having no linkage means there is no process
by which it can be made to refer to the same object or function as
those referred to by the same identifier in other declarations.
Since there is no means by which this declaration's identifier can
be made to refer to an entity associated with an identifier in
any other declaration, it seems appropriate to say there is "no
linkage" for this occurrence of the identifier.

> "If an identifier has no linkage, there shall be no more than one
> declaration of the identifier (in a declarator or type specifier)
> with the same scope and in the same name space, except for tags
> as specified in 6.7.2.3." [C99, 6.7]
>
> So, "no linkage" is in fact a kind of linkage, just with a poor
> name.

No, because the question of whether there is more than one
declaration of a given identifer (in the same scope, etc) does
not have to do with what entity it refers to but only what its
name is. You are confusing "linkage" with "spelling" (plus what
scopes and name spaces the various uses appear in, which again
do not depend on what objects or functions are referred to).

> Consider the situation
>
> { int x; int x; }
>
> which violates a constraint. But the diagnosis of the constraint
> violation requires x to be deemed as having linkage.

No, it doesn't.

> The diagnosis logically depends on:
>
> 1. An identifier is being declared more than once in the same
> scope.

This statement is correct.

> 2. That identifier refers to the same object or function.

This statement is incorrect. Any declaration of struct members
never refers to any object or function, and determining whether
the identifiers in the two declarations are the same does not
depend on what objects/functions they might refer to but only
how they are spelled.

> and these requires the "process called linkage".
>
> The process of looking up x in one declaration to see whether it
> was already mentioned by another declaration is linkage!

No, it's symbol table association, or some other term the
Standard doesn't define. The notion of 'linkage' is just about
whether two declarations of an identifier might refer to the
same object or function, which doesn't enter into the question
being addressed here.

> x has linkage, and it's just not allowed. So "no linkage" doesn't
> mean "lack of linkage" but something like "disallowed linkage".
>
> But the exception for struct and union tags shows that in fact
> some forms of "no linkage" are allowed. So the process by which
> two struct declarations arefer to the same struct, is evidently
> linkage of type "none". W00T?

Tags for struct and union (and enums) also have no linkage,
because they never can refer to the same object or function.
This obviously is true, because tags never refer to an
object or function under any circumstances.
I don't see any reason to prefer this approach to what the
Standard takes currently. There is still a need to associate
multiple declarations to a single object or function, you're
just not calling that association "linkage". Using the word
"linkage" for both external linkage and internal linkage seems
appropriate, as it is common for both to occur during a link
step rather than a compile step. Also, I think it might be
significantly harder under this approach to express all the
different combinations of declarations that C currently allows;
you might writing out your idea in Standardese to see what is
needed here -- it's not as easy as you might think.

Incidentally, your rule for when identifers may be redeclared
needs augmenting for C11's new provision for typedef names.

Kaz Kylheku

unread,
Apr 11, 2014, 12:37:02 AM4/11/14
to
On 2014-04-11, Tim Rentsch <t...@alumni.caltech.edu> wrote:
> Kaz Kylheku <k...@kylheku.com> writes:
>
>> Consider:
>>
>> "An identifier declared in different scopes or in the same scope
>> more than once can be made to refer to the same object or
>> function by a process called linkage. There are three kinds of
>> linkage: external, internal, and none." [C99, 6.2.2]
>>
>> How can "none" be a kind of linkage? [snip elaboration]
>
> Clearly an identifier having no linkage means there is no process
> by which it can be made to refer to the same object or function as
> those referred to by the same identifier in other declarations.
> Since there is no means by which this declaration's identifier can
> be made to refer to an entity associated with an identifier in
> any other declaration, it seems appropriate to say there is "no
> linkage" for this occurrence of the identifier.

But this "no linkage" is evidently one of the three kinds of linkage!

>> "If an identifier has no linkage, there shall be no more than one
>> declaration of the identifier (in a declarator or type specifier)
>> with the same scope and in the same name space, except for tags
>> as specified in 6.7.2.3." [C99, 6.7]
>>
>> So, "no linkage" is in fact a kind of linkage, just with a poor
>> name.
>
> No, because the question of whether there is more than one
> declaration of a given identifer (in the same scope, etc) does
> not have to do with what entity it refers to but only what its
> name is. You are confusing "linkage" with "spelling" (plus what
> scopes and name spaces the various uses appear in, which again
> do not depend on what objects or functions are referred to).

Linkage also doesn't have to do with what an entity the name
refers to.

And in fact, actual implementations of linkage happily link
incompatible declarations together, just because they have
the same name: "extern int x" in one unit, versus
"double x(void) { }" in another.

Definitions and declarations have semantics, but linkage
just deals with the proliferation of a name.

Tim Rentsch

unread,
Apr 18, 2014, 11:48:47 AM4/18/14
to
Kaz Kylheku <k...@kylheku.com> writes:

> On 2014-04-11, Tim Rentsch <t...@alumni.caltech.edu> wrote:
>> Kaz Kylheku <k...@kylheku.com> writes:
>>
>>> Consider:
>>>
>>> "An identifier declared in different scopes or in the same scope
>>> more than once can be made to refer to the same object or
>>> function by a process called linkage. There are three kinds of
>>> linkage: external, internal, and none." [C99, 6.2.2]
>>>
>>> How can "none" be a kind of linkage? [snip elaboration]
>>
>> Clearly an identifier having no linkage means there is no process
>> by which it can be made to refer to the same object or function as
>> those referred to by the same identifier in other declarations.
>> Since there is no means by which this declaration's identifier can
>> be made to refer to an entity associated with an identifier in
>> any other declaration, it seems appropriate to say there is "no
>> linkage" for this occurrence of the identifier.
>
> But this "no linkage" is evidently one of the three kinds of linkage!

This kind of construction is common in regular English, eg

"What kind of insurance do you have?"

"No insurance."

I don't know anyone else who is bothered by this.

Kaz Kylheku

unread,
Apr 18, 2014, 2:33:12 PM4/18/14
to
The reply can be hypothesized as being derived from the sentence
"I have no insurance", by elision of subject and verb.

It can also be hypothesized as an elision of "The kind of insurance
I have is no insurance", though this seems less plausible.

It would also be odd to say things like, "At Sunlife, we offer you two major
kinds of insurance: actual insurance (coverage of specified perils for a
premium) and no insurance (no coverage at all, but free)."

Yet this appears to be similar to what the standard is doing with "no linkage",
except that no linkage actually links!

There is a glaring defect in 6.7:

"Each declaration of an identifier with no linkage denotes a unique entity."

This is false for repeated declarations of tags where the second declaration
is in scope of the first. They denote the same type entity.

Really, there should be three kinds of linkage: external, internal and tag.
Plus, the situation that identifiers have on linkage.

Then, for instance, the constraint paragraph 2 under 6.7 would not have to
give an exception for tags.

If an identifier has no linkage, there shall be no more than one declaration
of the identifier (in a declarator or type specifier) with the same scope and
in the same name space, except for tags as specified in 6.7.2.3.

If "no linkage" is not a kind of linkage, then the above clearly has the
intuitive meaning: an identifier without linkage. And if tags have "tag
linkage", the "except for tags" text becomes superfluous.

Tag linkage neatly explains why these declarations are connected (i.e. linked)
to the same type:

struct foo;
void func(void) { struct foo; }

and absence of linkage explains why the second x is not linked to the
first:

struct x;
void func(void) { struct x; }

tag linkage is strongly tied to lexical scopes, whereas internal and external
linkages aren't but that doesn't mean it can't be a kind of linkage.

Tag linkage already exists; it just isn't formally recognized.

By the way, the tags in the example:

struct foo;
void func(void) { struct foo; }

are still in different lexical scopes. We know they are separate scopes because
if we complete the type in the inner scope, the completion does no propagate to
the outer scope:

struct foo;
void func(void) { struct foo { int memb; }; }

// the complete foo with memb is not known at this point!!!
struct foo s = { 3 }; // error: definition with incomplete type

So the compiler has to maintain a separate scope for the inner foo.
Moreover, this inner foo shadows the outer foo: the inner foo is complete
where as the outer isn't! References to foo in the inner scope access
the complete type. Yet, they are connected: they refer to the same type. I
can't think of a reason not to call that connection between identifiers in
separate scopes "linkage".
0 new messages