This code will compile and is well defined under current C standards:
static int foo(int);
extern int foo(int);
The standard specifies that
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).
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
}
}