Extern Keyword in Global Scope

94 views Asked by At

According to the c documentation on storage class specifiers (using the well known cpp reference website): https://en.cppreference.com/w/c/language/storage_duration, "Storage-class specifiers appear in declarations.... if no storage-class specifier is provided, the defaults are:

  1. extern for all functions
  2. extern for objects at file scope
  3. auto for objects at block scope"

So, when we have a definition of a file scope variable, i, in one file:

file1.c

int i = 0;

How would it even be possible at file scope (in another file) to have both (1) no storage class specifier and (2) only a declaration of the variable. Because a file scope variable is initialized and defined if there is no extern keyword it seems that the variable can only either be defined resulting in a compiler error:

file2.c

int i;

or declared with extern keyword:

file2.c

extern int i;

Thus, I don't understand how their can both be a declaration and no storage class specifier at file scope. I may be getting too much into the semantics but it doesn't make sense to have a default declaration at file scope that defaults to extern. Any help would be appreciated!

1

There are 1 answers

0
Eric Postpischil On

[From the question] …(using the well known cpp reference website)…

cppreference.com is not an authoritative reference for C or C++ and has numerous deficiencies. When issues arise in it, you should refer to the C or C++ standards.

[From the question] “Storage-class specifiers appear in declarations.... if no storage-class specifier is provided, the defaults are:…”

Although the text you elided says “The storage-class specifiers determine two independent properties of the names they declare: storage duration and linkage,” this passage is constructed to give the (incorrect) impression that if no storage-class specifier is provided, the semantics are as if one of the defaults it lists were provided as a storage-class specifier.

That is false. In various cases, the semantics of a declaration without any storage-class specifier have differences from a declaration with storage-class specifier.

When int i; appears at file scope, it has static storage duration and external linkage, the same as if extern int i; had been used. However, these are different in that int i; is a tentative definition and extern int i; is a declaration.

Note that in spite of what its name suggests, a tentative definition is not actually a definition, just as a prospective employee on a job interview is not an employee. int i; is a declaration that is not a definition.

Consider a translation unit containing:

int i;
int i;
int i = 3;
int i;

In this case, int i = 3; is a definition, and the tentative definitions have no effect other than as declarations. Their semantics are governed by the rules for declarations, and nothing in the C standard says they are definitions of i.

Alternatively, consider:

int i;
int i;
int i;

In this case, these tentative definitions are again declarations, but C 2018 6.9.2 2 tells us that, in effect, a definition is created for i at the end of the translation unit:

[C 2018 6.9.2 2] … If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.

[From the question] How would it even be possible at file scope (in another file) to have both (1) no storage class specifier and (2) only a declaration of the variable.

int i; has no storage class specifier and is a declaration that is not a definition. How it behaves is governed by the rule in C 2018 6.9.2 2; it does not behave the same way as either extern int i; or int i = 0;.

[From the title] Extern Keyword in Global Scope

C does not have a global scope. It has file scope, which is different. In a programming language with global scope, declaring an identifier at global scope makes it known throughout the program. In C, declaring an identifier at file scope makes it known only in the translation unit of the declaration, not the entire program. To make it known elsewhere in the program, it must be declared elsewhere and linked.