Going by the excellent cppreference.com (from the C language section), there appears to be a ‘tentative’ variable declaration, so:
-
int i = 3 is assumed to be extern
-
int i is assumed to be ‘tentative’
Quoting from the same:
A tentative definition is a declaration that may or may not act as a definition. If an actual external definition is found earlier or later in the same translation unit, then the tentative definition just acts as a declaration.
It’s definitely a bit confusing. Or at least I find it so.
The GCC docs for -fno-common are also useful.
-fno-common
In C code, this option controls the placement of global variables defined without an initializer, known as tentative definitions in the C standard. Tentative definitions are distinct from declarations of a variable with the extern keyword, which do not allocate storage.
Unix C compilers have traditionally allocated storage for uninitialized global variables in a common block. This allows the linker to resolve all tentative definitions of the same variable in different compilation units to the same object, or to a non-tentative definition. This is the behavior specified by -fcommon, and is the default for GCC on most targets. On the other hand, this behavior is not required by ISO C, and on some targets may carry a speed or code size penalty on variable references.
The -fno-common option specifies that the compiler should instead place uninitialized global variables in the data section of the object file. This inhibits the merging of tentative definitions by the linker so you get a multiple-definition error if the same variable is defined in more than one compilation unit. Compiling with -fno-common is useful on targets for which it provides better performance, or if you wish to verify that the program will work on other systems that always treat uninitialized variable definitions this way.
There is more information out there if you you Google “-fno-common”, there are some links that discuss what the linker does and the .COMMON block.
Personally I think I will enable -fno-common on all my C projects (not that I have any).
(FYI, C++ doesn’t have this issue.)