It is generally best if the header uses extern int a;
. See also How do I share a variable between source files in C?
The standard says:
ISO/IEC 9899:2011 §6.9.2 External object definitions
Semantics
¶1 If the declaration of an identifier for an object has file scope and an initializer, the
declaration is an external definition for the identifier.
¶2 A declaration of an identifier for an object that has file scope without an initializer, and
without a storage-class specifier or with the storage-class specifier static
, constitutes a
tentative definition. 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.
Thus, what's in the header is a tentative definition of the variable. At the end of the translation unit (TU) for file5.c
, you have no longer got a tentative definition; the 'external definition' specified by int a = 20;
has specified that. At the end of the TU for file6.c
, you have a definition equivalent to int a = 0;
.
When you try to link file5.c
and file6.c
, you should run into multiple definitions of a
. However, there is a common extension, documented in the standard in Annex J:
J.5.11 Multiple external definitions
¶1 There may be more than one external definition for the identifier of an object, with or
without the explicit use of the keyword extern
; if the definitions disagree, or more than
one is initialized, the behavior is undefined (6.9.2).
Your compiler is providing the extension identified by §J.5.11, and therefore (legitimately) not complaining.
580