In C, both variables and functions have external linkage at file scope by default. Why is the keyword extern
only required for variables but not functions that are defined elsewhere? Note that there are two aspects to this question. Given that declarations at file scope default to external linkage:
- Why historically is there no distinction for functions in whether their declaration has
extern
or not? Or, why objectively is no such distinction needed? - Why historically is there a distinction for variables in whether their declaration has
extern
or not? Or, why objectively is such a distinction needed?
For a minimal example, let's use the following two source files (tu
stands for "translation unit").
tu1.c
:
extern int i = 123;
tu2.c
:
#include <stdio.h>
extern int i;
int main(void) {
//extern int i;
++i;
printf("%d\n", i);
return 0;
}
We can compile them with GCC as follows:
gcc -c tu1.c
gcc -c tu2.c
gcc -o myprogram tu1.o tu2.o
(GCC issues the warning 'i' initialized and declared 'extern'
for the first command, because it erroneously believes that extern
"should be reserved for non-defining declarations". We can safely ignore it.)
Let's compare how the compiler behaves for slightly different versions of the source code:
extern int i;
at file scope intu2.c
(no change to the above code):
The output ofmyprogram
is124
, as expected.extern int i;
inmain
(instead of at file scope) intu2.c
:
This works equally well (but this style is not recommended: "A function should never need to declare a variable usingextern
.").- not declaring
i
anywhere intu2.c
:
This doesn't work; for linei++;
we get the following error:'i' undeclared (first use in this function)
. int i;
withoutextern
at file scope intu2.c
:
This fails with an error:multiple definition of `i'
.
I am wondering about the rationale for the last case: If a bare (extern
-less) int i;
defaults to external linkage, why do we need to supply the keyword extern
explicitly? The answer seems to be in the standard (C99: 6.9.2 External object definitions), according to which int i;
is a tentative definition, instantiated to an actual definition upon compilation. The logic would be that supplying the extern
keyword instructs the compiler to treat the resulting construct as a declaration-which-is-not-a-definition. But if this is so: Why doesn't the same logic hold for function prototypes, for which it is well-known that extern
is implicit?
I have a feeling that the right answer is related or close to this answer to "What is the rationale behind tentative definitions in C?", but I would like to know what would specifically go wrong if variables and functions were treated the same in the above regard.
There is a similar question about C++ and a relevant article by Peter Goldsborough.
Note for people used to programming in C++:
- In C, variables at file scope (incl
const
ones) and functions default to external linkage. - In C++, there is the subtle difference that
const
global variables default to internal linkage.