Reputation: 1848
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:
extern
or not? Or, why objectively is no such distinction needed?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 in tu2.c
(no change to the above code):myprogram
is 124
, as expected.extern int i;
in main
(instead of at file scope) in tu2.c
:extern
.").i
anywhere in tu2.c
:i++;
we get the following error: 'i' undeclared (first use in this function)
.int i;
without extern
at file scope in tu2.c
: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++:
const
ones) and functions default to external linkage.const
global variables default to internal linkage.Upvotes: 4
Views: 749
Reputation: 11377
A function declaration (without a body) is obviously just a declaration. That's why the storage class specifier extern
is implicit.
A variable declaration (withoutextern
), on the other hand, is also a definition. Adding extern
to the variable declaration T x;
means "somewhere there should be a definition of a variable x of type T".
If you practice modular programming there is no use for extern variables declarations since all variables declared outside of a function should have static
storage class and be accessed through one of the functions from the module's API. In some situations though you may need the extra efficiency of accessing or assigning to a variable directly but then the extern declaration should be placed in the module's header file.
Upvotes: 1
Reputation: 222526
Because the form of a function declaration indicates whether it is a definition or not.
A function declaration without a body is not a definition:
void foo(void);
A function declaration with a body is a definition:
void foo(void) { }
With int x;
, there is ambiguity. Early C implementations treated this in different ways. We can mark it as definitely a definition by giving an initializer:
int x = 0;
However, with just int x;
, some C implementations treated this as a definition (and may have allowed multiple such definitions to be coalesced into one, so this declaration appearing in a header file included in multiple translation units would result in just one definition in the linked program).
To remove the ambiguity, using extern
without an initializer makes it a declaration that is not a definition.
If we were designing C from scratch, we could make a rule that int x;
outside of any function is a declaration that is not a definition and that int x = 0;
is a definition. So the current state of the language is not a logical necessity; it is a consequence of the history of how the language developed.
(However, such a rule would contrast with how we use declarations inside functions. Inside a function, we are accustomed to int x;
being a definition. If we adopted the above rule for declarations outside functions, we would have to either live with the contrast between declarations inside functions with those outside functions or were would have to adopt the same rule for declarations inside functions.)
Upvotes: 5
Reputation: 67476
It is to make a clear difference between declaration
and definition
.
Function prototype is clearly a declaration, not definition
int x;
is definition so something else is needed to show the compiler that we do not define object x
only declare it. extern int x;
does it
Upvotes: 1