Question

I am aware about C linking rules presented in the following excerpts from C standard:

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

4/ 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.

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.

I understand that extern keyword is optional before functions declarations because they are external by default but there are some functions prototypes preceded by extern in stdlib.h such as:

extern void qsort (void *__base, size_t __nmemb, size_t __size,
           __compar_fn_t __compar) __nonnull ((1, 4));

Also, why gcc handles situations described in point 7 differently when it comes to functions and variables. In this example both function foo and variable d are defined both in internal and external scope but only variable definition raises error:

static int foo(void); 
int foo(void); /* legal */

static double d;
double d; /* illegal */
Was it helpful?

Solution

One can freely place or not place extern before function declaration, so it should not be surprising that one can found it somewhere. Regarding second question:

C11 draft (n1570.pdf) has example in page 159 related to tentative definitions:

static int i5; // tentative definition, internal linkage
// ...
int i5; // 6.2.2 renders undefined, linkage disagreement
extern int i5; // refers to previous, internal linkage

6.2.2 is what you have posted. So, it does not work in this case because there are two tentative definitions with different linkages, so there is p.7 violation. On the other hand, it works with external specifier (as foo functions from your example), because p.4 is enforce - later declaration refers to linkage defined in first declaration. In other words, case with variables does not work because they are objects and tentative definition rules are involved. At least standard contains explicit example which clearly explains what comittee wanted to say.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top