static int i;
int i;
is valid at file scope, yet:
int i;
static int i;
is not.
The reason is surprisingly complicated.
Before we can say why the first is OK and the second is not, we
will need a good grasp of identifiers and their properties.
Identifiers themselves are fairly straightforward. For the most
part, they are just names that start with an alphabetic character,
and go on to include alphanumerics. Hence "i", "main", "a2b", and
so on are all (once you remove the double quotes) valid identifiers.
Identifiers name things, like variables, functions, and even macros.
The trick is deciding which things they name, and in turn, what
those things are.
In this case, "i" names an ordinary variable -- but all identifiers
have a number of special properties. Two important ones are "scope"
and "name space". A third, and one which becomes crucial soon, is
"linkage", but we should consider scopes and name spaces first.
The scope of an identifier essentially controls its visibility
within a given "translation unit" (roughly, "source file after
expanding #include directives"). If you have done much C programming
at all, you will be familiar with both file-scope and narrower-scope
identifiers:
int shared;
void f(void) {
int i;
...
}
void g(void) {
int i;
...
}
Here the two "i"s each have "block scope", so that the "i" in f()
is completely different from the "i" in g(). Neither "i" can be
named outside the corresponding function -- trying to use f()'s "i"
in another function h() simply will not work; it cannot be named
there. On the other hand, the variable called "shared" is visible
inside both f() and g(), and would be visible in h() if we added
it below these, unless we declared a block-scope variable also named
"shared" (which would then hide or "shadow" the outer one).
The C Standard states quite clearly that two identifiers have the
same scope if and only if their scopes terminate at the same point.
(Many of the things the Standard says are not very clear, but this
one is.) Block scopes end at the ending of their enclosing block,
while file scope does not end until the end of the translation
unit. All of this means that the name "i" in f() refers to f()'s
"i", because that i's scope ends at f()'s final close brace, and
so on. Re-using the name "shared" -- including any attempt to
re-declare it -- refers to the file-scope variable, unless the
re-declaration is in an inner scope, such as:
void h() {
int shared; /* UGH, shadows file-scope variable */
/* Do not do this if you can possibly avoid it. */
/* It confuses people who have to maintain the code later. */
}
or unless "shared" is in a different "name space".
C's name spaces are relatively primitive compared to other languages.
Probably the most straightforward example is struct and union tags.
These tags are in the "tag name space" and never collide with
ordinary variables. This means you may write, e.g.:
struct glorp {
int a;
char *b;
} glorp;
The ordinary variable "glorp" is in the ordinary-variable namespace,
while the tag "glorp" in "struct glorp" is in the structure tag
name space, so these are two different "glorp"s. (I tend to think
of them as "the regular glorp" and "the struct glorp", myself, with
the word "struct" as part of the name. Of course, I also think of
the word "struct" as standing for "STRangle spelling for User-defined
abstraCt Type", and hence read it as if it were the word "type" in
some other language.
)
Here, in the example that kicks off the whole problem, the identifier
"i" is in the ordinary namespace, so we can pretty much ignore the
whole issue. Still, it is something to keep in mind: you can re-use
the same names for different things, even in the same scopes, as
long as they are in different name-spaces. (In general, it is
probably wise to limit such re-use, for the same reason that it is
generally bad to "shadow" outer-scope variables -- it gets confusing.)
Finally, we get to "linkage" of identifiers. Linkage is the means
by which separate translation units can "meet up with each other",
as it were. An identifier that has "external linkage" is visible
outside its translation unit. An identifier with "internal linkage"
or "no linkage" -- these are the only other possibilities -- is
not. This means that "internal linkage" variables do not "escape"
outside the translation unit. When you are working on large
projects, knowing that some variable cannot be seen outside some
given source module can be very helpful, so making your file-scope
variables "static" whenever possible is often a good idea. (It
is helpful because it means you can avoid searching for other uses
of that variable, and avoiding work is good.
)
We now have almost everything we need to answer the question -- which,
in case you forgot, is:
"
static int i;
int i;
is valid at file scope, yet:
int i;
static int i;
is not. Why?"
I say "almost everything" because we now get into the places where
C really gets confusing.
A file-scope variable invariably has some -- i.e., not "no" --
linkage, either "internal" or "external". It also always has
"static duration" -- something I have not mentioned above -- and
(obviously) "file scope".
Duration is not a property of identifiers, but rather of variables,
or more precisely, of "objects". There are three durations:
"static", "automatic", and "allocated". This "static" is only
partly connected to the "static" keyword. In this case, we are
dealing with file-scope objects (variables), which *always* have
static duration, so the "static" keyword cannot possibly change
the duration. Instead, the "static" kewyord, in this particular
case, affects the linkage.
As nonsensical as this may seem, the "static" keyword has two
meanings. For block-scope variables, it changes their duration,
but for file-scope variables, it changes their linkage. (In C99,
the "static" keyword has yet another new meaning; fortunately, we
can ignore that entirely here.)
Without the "static" keyword, a file-scope variable usually winds
up with external linkage. Adding "static" tells the compiler:
"this identifier is to have internal linkage."
There is another keyword you can use here, the "extern" keyword.
This keyword is just as misleading as "static". You might think:
"extern, ah, that must mean external linkage"; but if you did, you
would be wrong.
As usual, C's keywords are twisted around.
The default for file-scope variables is external linkage, so C does
not *need* a keyword to specify that. Instead, putting "extern"
in front of a file-scope variable declaration has the effect of
removing "tentative definition-ness" (which I have not explained,
and will not here). Moreover, leaving out both "extern" *and*
"static" has the same effect on linkage as using an explicit "extern"
(you just get that "tentative definition" thing). And now things
get *really* bizarre, because...
Aside from suppressing tentative definitions, the "extern" keyword
gives these identifiers the *same* linkage as any file-scope
declaration already visible. If no such declaration is visible,
"extern" gives the identifier external linkage. In particular,
this means that, in:
static int internal_linkage;
extern int internal_linkage; /* surprise! */
the second line *means* "static" even though it *says* "extern"!
*Now* we finally have all the pieces, and can answer the original
question. Consider the first code fragment:
static int i;
int i;
Here we have two file-scope declarations for the identifier "i".
The first one gives "i" internal linkage. The second one does not
use the "extern" keyword (and is thus a tentative definition --
not that it matters since the first declaration is already a
tentative definition as well), but has the same linkage effect
as if it did. Since the first declaration is already in scope,
this "extern" refers back to it and gives this second "i" internal
linkage. So this is really two "static int i;" lines, even
though the second one uses the implied "extern" keyword to mean
"static-style linkage".
On the other hand, the second fragment reads:
int i;
static int i;
Here the first line has an implied "extern" as far linkage goes,
but this time there is no "i" in scope. The "extern" cannot find
a previous declaration to refer back to, and thus gives this "i"
external linkage. The second line then declares "i" again, but
this time says it should have internal linkage. The C standard
says that the effect here is undefined, but a good C compiler will
produce some kind of message ("warning", or "error", or electric
shock to the programmer, or some such) to alert you and give you
a chance to fix the code.