This has to do with something called "tentative definition" in C. First, if you assign to global
in both file1 and file2, you will get an error in C. This is because global
is not tentatively defined in file1 and file2 anymore, it is really defined.
From the C standard (emphasis mine):
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.
For your case, "translation unit" (basically) each source file.
About "composite types":
For an identifier with internal or external linkage declared in a scope in which a prior
declaration of that identifier is visible, if the prior declaration specifies internal or
external linkage, the type of the identifier at the later declaration becomes the composite
type.
For more on tentative definitions, see this question and its answers.
It seems like for your case, it should be undefined behavior because global
is defined at the end of the translation units, so you get two definitions of global
, and what's worse, they are different. Looks like the linker by default doesn't complain about this though.
GNU ld has an option called --warn-common
, which warns you for multiple tentative definitions (common symbol is linker's name for tentatively defined variables):
$ gcc -Wl,--warn-common file*.c
/tmp/ccjuPGcq.o: warning: common of `global' overridden by larger common
/tmp/ccw6nFHi.o: warning: larger common is here
From the manual:
If there are only (one or more) common symbols for a variable, it goes in the uninitialized data area of the output file. The linker merges multiple common symbols for the same variable into a single symbol. If they are of different sizes, it picks the largest size. The linker turns a common symbol into a declaration, if there is a definition of the same variable.
The --warn-common
option can produce five kinds of warnings. Each warning consists of a pair of lines: the first describes the symbol just encountered, and the second describes the previous symbol encountered with the same name. One or both of the two symbols will be a common symbol.