I have been investigating when it is possible to mix variables declared with extern
, static
and no storage specifier in global scope. The results have left me quite confused.
This is what I found (each paragraph is a separate compilation unit):
/* ok */
int x;
int x;
/* ok */
int f();
int f();
/* ok */
int x;
extern int x;
/* ok */
int f();
extern int f();
/* error: static declaration follows non-static declaration */
int x;
static int x;
/* ok (no warning) */
int f();
static int f();
/* ok */
extern int x;
int x;
/* ok */
extern int f();
int f();
/* ok */
extern int x;
extern int x;
/* ok */
extern int f();
extern int f();
/* error: static declaration follows non-static declaration */
extern int x;
static int x;
/* error: static declaration follows non-static declaration */
extern int f();
static int f();
/* error: non-static declaration follows static declaration */
static int x;
int x;
/* ok (no warning) */
static int f();
int f();
/* ok */
static int x;
extern int x;
/* ok */
static int f();
extern int f();
/* ok */
static int x;
static int x;
/* ok */
static int f();
static int f();
I get the same exact results with gcc
and clang
but I cannot find a pattern in what works and what doesn't work.
Is there any logic here?
What does the C standards say about mixing global declarations declared with extern
, static
and no storage specifier?
If you define an identifier without the keyword static
, it's published in the object file and can be accessed by other modules. So if you again define that identifier without static
in another module, you'll get a conflict: two published identifiers.
If you use the keyword
static
, then (most of) the rest of this doesn't apply.
The problem is the difference between declaring the identifier and defining it. The first says "there's going to be an identifier X
with this type". The second says "here's something that I'm going to call X
of this type".
With functions it's easy: don't provide the body, and it's merely a declaration. Provide the body, and it's a definition too. You can use extern
to make this explicit in a header file but since it's the default, that's not usual.
With variables it's harder. Simply declaring the variable defines it too - thus you can initialise it while defining it. If you want to only declare it, you need to use the keyword extern
- but then you can't initialise it too. You're saying "there's going to be a variable called X
" - so you can't have the temerity of deciding its definition too!
That's why in header files all variables should be explicitly declared either extern
or static
:
extern
keyword, with an optional initialisation value.