On 4/10/25 08:46, David Brown wrote:
...
There have been a variety of things under discussion here, but I think
this particular one was about the linkage rules in C if an identifier is
declared with "static int foo;" and/or "extern int foo;" and/or "int
foo;" at file scope, possibly in different orders. My thought was that
one influence on the rules was consistency of existing code after
"extern" was added to the language, but it seems unlikely since no one
knows of an early C without "extern".
So currently, I have no explanation for why you may write "static int
foo; extern int foo;" and have "foo" be internal linkage, while "extern
int foo; static int foo;" is not allowed. Given that neither are likely
to be of the remotest use, nor likely to be written by accident and go
unnoticed, it should not affect anyone significantly.
But if someone else has an explanation for this, or a realistic use-case
for static followed by extern, I am curious to hear about it.
According to the C89 Rationale
"The Standard requires that the first declaration, implicit or explicit,
of an identifier specify (by the presence or absence of the keyword
static) whether the identifier has internal or external linkage. This
requirement allows for one-pass compilation in an implementation which
must treat internal linkage items differently than external linkage
items. An example of such an implementation is one which produces
intermediate assembler code, and which therefore must construct names
for internal linkage items to circumvent identifier length and/or case
restrictions in the target assembler.
The definition model to be used for objects with external linkage was a
major standardization issue. The basic problem was to decide which
declarations of an object define storage for the object, and which
merely reference an existing object.
A related problem was whether multiple definitions of storage are
allowed, or only one is acceptable. Existing implementations of C
exhibit at least four different models, listed here in order of
increasing restrictiveness:
*Common* Every object declaration with external linkage (whether or not
the keyword extern appears in the declaration) creates a definition of
storage. When all of the modules are combined together, each definition
with the same name is located at the same address in memory. (The name
is derived from common storage in FORTRAN.) This model was the intent of
the original designer of C, Dennis Ritchie.
*Relaxed Ref/Def* The appearance of the keyword extern (whether it is
used outside of the scope of a function or not) in a declaration
indicates a pure reference (ref), which does not define storage.
Somewhere in all of the translation units, at least one definition (def)
of the object must exist. An external definition is indicated by an
object declaration in file scope containing no storage class indication.
A reference without a corresponding definition is an error. Some
implementations also will not generate a reference for items which are
declared with the extern keyword, but are never used within the code.
The UNIX operating system C compiler and linker implement this model,
which is recognized as a common extension to the C language (F.4.11).
UNIX C programs which take advantage of this model are standard
conforming in their environment, but are not maximally portable.
*Strict Ref/Def* This is the same as the relaxed ref/def model, save
that only one definition is allowed. Again, some implementations may
decide not to put out references to items that are not used. This is the
model specified in K&R and in the Base Document.
*Initialization* This model requires an explicit initialization to
define storage. All other declarations are references.
Figure 3.1 demonstrates the differences between the models.
The model adopted in the Standard is a combination of features of the
strict ref/def model and the initialization model. As in the strict
ref/def model, only a\ single translation unit contains the definition
of a given object | many environments cannot effectively or efficiently
support the \distributed definition" inherent in the common or relaxed
ref/def approaches. However, either an initialization, or an appropriate
declaration without storage class specifier (see x3.7), serves as the
external definition. This composite approach was chosen to accommodate
as wide a range of environments and existing implementations as possible."