简体   繁体   中英

Can Someone Explain The Linkage Concept in C in Detail

I have following C program:

#include<stdio.h>

static void p(void);
static int c;

int main(int argc,char **argv) {
    p();
    printf("%d",c);
    return 0;
}


void p(void) {
    printf("From the Function P\n");
}

int c=232;

And the output error of compiler gcc is : error: non-static declaration of 'c' follows static declaration

and when i looked in C standard ISO/IEC 9899:TC2 :


6.2.2 Linkages of identifiers

1 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.21) There are three kinds of linkage: external, internal, and none.

2 In the set of translation units and libraries that constitutes an entire program, each declaration of a particular identifier with external linkage denotes the same object or function. Within one translation unit, each declaration of an identifier with internal linkage denotes the same object or function. Each declaration of an identifier with no linkage denotes a unique entity.

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

4 For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible ,23) 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 .

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

6 The following identifiers have no linkage: an identifier declared to be anything other than an object or a function; an identifier declared to be a function parameter; a block scope identifier for an object declared without the storage-class specifier extern.

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

21) There is no linkage between different identifiers. 22) A function declaration can contain the storage-class specifier static only if it is at file scope; see 6.7.1.


Q.1 i can not understand the rule 4 and 5? what is the difference btw linkage is determined exactly as if it were declared with the storage-class specifier extern. and linkage is external


Q2. why this error comes as i can infer from rule 5 that c has static decl. followed by extern decl. so last decl.shud also be static.? i wud appreaciate if some one takes pain to explain all the rules from beginning..or suggest me a link that explaints all the rules clearly.*

Note: thnx for any suggestions to edit this question properly cuz it may be duplicate i asked this question becuz i could not understand the answers of similar questions posted on this site thnx in advance.

First, bear in mind that the sections of the standard quoted here are referring to two separate things: 1. function declarations 2. object (eg, variable) declarations. Your question seems to show some confusion between the two.

As rule 2 says, functions or objects declared with keyword static have internal linkage only. That is, they are not visible outside the current translation unit. When you first declare static int c , you are saying that c has internal linkage only and cannot be seen outside this translation unit. You are declaring this variable outside any function, ie, you are giving it file scope.

Later, you re-declare int c = 232 . You are declaring this variable in file scope as well--it is not inside any function. Rule 5 says:

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

Since you are declaring it with file scope and without any storage-class specifier, it defaults to external linkage.

These two declarations of int c contradict each other: the first one, with static , specifies internal linkage; the second, with no storage-class specifier, defaults to extern . Because of this contradiction, you are getting the error that you see from GCC.

Rule 4 says:

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. 

But this refers specifically with identifiers re-declared as extern . This means that if you re-declare c as follows: extern int c = 232 , you will not get the error. (You may, however, get a warning.) When I used the extern keyword before the second declaration, I got the following output as expected:

From the Function P
232

Why does this work? The Rationale for the C standard provides the explanation:

The appearance of the keyword extern in a declaration, regardless of whether it is 
used inside or outside of the scope of a function, indicates a pure reference (ref), 
which does not define storage. Somewhere in all of the translation units, at least 
one definition (def) of the object must exist. An external definition is indicated 
by an object declaration in file scope containing no storage class indication. 
                                                                 // § 6.2.2, p. 33

When you first declare static int c and then declare int c = 232 the second time without the keyword extern , the compiler attempts to set aside storage for c again--it attempts to redefine c . But since c is already in scope, this second definition will fail, and you will get the error.

When you explicitly redeclare it as extern c = 232 , the extern keyword specifies that this is not a new object for which storage needs to be set aside; the storage is elsewhere. Since c is already in scope from the earlier static declaration, the second declaration does not overwrite it; it sets the value of that static c variable to 232.

This is useful if you have a function within that file which needs to set the value of that static variable:

static int c;

void funA (void) {

  extern int c = 232;    // "extern" specifies that this is not new storage

}

As for Rule 5, the first sentence says simply that functions are extern by default unless they are specified as static ; the second sentence says that global variables (declared at file scope) are extern by default. If I declare a function inside another function, it still has extern scope; a variable declared inside a function, however, has automatic storage, and is not in scope outside that function. To clarify:

int foo;          
extern void funA (void);

void funB (void) {

    int foo;     // hides global int foo, but has scope only within funB()
    int bar;     // has scope only within funB()
    .... 
}

void funC (void) {

    int funD (int, int);   // has extern scope even though is declared within funC()
    extern int foo = 20;   // sets value of global variable foo declared at file level
    ....
}

Hope this helps!

static int c; means c is having file scope and internal linkage because of static but later defining c again as int c without any storage class specifier tries to give it external linkage by default (rule 5)) which is against as it was declared earlier in the same file scope.

Identifiers that have external linkage can be seen across different translation units that are linked together into an executable. Identifiers that do not have external linkage can only be seen in (perhaps only in a particular scope of) the translation unit that defined it. From C.99 §5.1.1.1:

The separate translation units of a program communicate by (for example) calls to functions whose identifiers have external linkage, manipulation of objects whose identifiers have external linkage, or manipulation of data files. Translation units may be separately translated and then later linked to produce an executable program.

For an illustration of C.99 §6.2.2 ¶4, consider the following:

static int c;
void foo () { assert(c == 1); }
int main () {
    extern int c;
    c = 1;
    foo();
    return 0;
}

The assertion condition will evaluate to true. This is because C.99 §6.2.2 ¶4 says that the c in extern int c takes on the same linkage of some previously declared c if there is one in scope, which in this case is the static int c . If there was no declaration of c , then then extern int c in main() would have external linkage.

In C.99 §6.2.2 ¶5, the first sentence only applies to function names. It is saying that if a function declaration does not contain any storage class, then the function name has external linkage.

The second sentence in C.99 §6.2.2 ¶5 states that if an object is declared at file scope without any storage class, then the name of that object will have external linkage. Thus, in your snippet:

static int c;
/*...*/
int c = 5;

There is a conflict since c is first declared to have internal linkage, and then later to have external linkage.

Regarding Q1:

In the paragraph 5 you quote, the first sentence applies only to an identifier for a function . In int c=232; , c is an identifier for an object , not a function. Therefore, the first sentence does not apply.

The second sentence applies to an identifier for an object. It says that, for a declaration at file scope and without a storage-class specifier, the linkage is external.

Therefore, in the int c=232; in your question, the linkage is external.

Regarding Q2:

As we now see, the first declaration, static int c; , gives c internal linkage, and the second declaration, int c=232; , gives c external linkage. These conflict, so it is an error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM