This code will compile and is well defined under current C standards:
static int foo(int);
extern int foo(int);
The standard specifies that in this situation (C11: 6.2.2 Linkages of identifiers (p4)):
For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,31) 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. [...]
... which means that the int foo(int)
function is declared static int foo(int)
.
Swapping these declarations around like this:
extern int foo(int);
static int foo(int);
...gives me a compiler error using GNU GCC:
static declaration of 'foo' follows non-static declaration
My question is: What is the design rationale behind the second case being an error and not handled in a similar way as the first case? I suspect it has something to do with the fact that separate translation units are easier to manage and #include
? I feel as though without understanding this, I can open myself up to some mistakes in future C projects.
I think the idea of this confusing specification is that an extern
declaration can be used inside a function to refer to a global function or object, e.g to disambiguate it from another identifier with the same name
static double a; // a declaration and definition
void func(void) {
unsigned a;
.....
if (something) {
extern double a; // refers to the file scope object
}
}
Whereas if you use static
you declare something new:
extern double a; // just a declaration, not a definition
// may reside elsewhere
void func(void) {
unsigned a;
.....
if (something) {
static double a; // declares and defines a new object
}
}
I can imagine that the scenario leading to this asymmetry is that the default linkage of identifiers at global scope is extern
.1 Failing to mark the definition of a previously static-declared function static
as well would otherwise be an error because it is by default also an extern
declaration.
Here is an illustration. In modern C, functions must be declared before use, but sometimes the implementation is at the end because it is secondary to the main purpose of the code in the file:
static void helper_func(); // typically not in a header
// code using helper_func()
// And eventually its definition, which by default
// declares an **external** function. Adding
// an explicit `extern` would not change a thing; it's redundant.
void helper_func() { /* ... */ }
This looks innocent enough, and the intent is clear. When C was standardized there was probably code around looking like this. That's why it is allowed.
Now consider the opposite:
extern void func(); // this could be in a header
// ... intervening code, perhaps a different file ...
static void func() { /* ... */ }
// code which uses func()
It's pretty clear that this should not be allowed. Defining a function static
is a clear, explicit statement. A prior, contradicting extern
declaration does not make sense.2 There is a good chance that this is an inadvertent name collision, for example with a function declared in a header. Probably not much code out there was looking like this at the time of formalization. That's why it is forbidden.
1 From the C17 draft, 6.2.2/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."
2 One could argue that an explicit extern
declaration using the keyword, followed by a static
definition, should be forbidden while an implicit one, without the keyword, could still be allowed (and that, correspondingly, a later explicitly extern
function definition after a static
declaration should be forbidden, while implicit ones are still allowed). But there is a limit to the hair-splitting a standard should do (and it's gone pretty far already).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With