I know some basic usage of extern, but one thing really bothers me.
The following picture is what I found in the specification.
If it is really as shown in the picture, why are the following two pieces of code different?
#include <stdio.h>
int i;
int main() {
printf("i = %d\n", i);
return 0;
}
#include <stdio.h>
extern int i;
int main() {
printf("i = %d\n", i);
return 0;
}
Additionally, the following code will have a warning:
warning: ‘i’ initialized and declared ‘extern’
WHY?
extern int i = 0;
Can someone tell me what the hell is going on with extern?

The text in the image is wrong because “extern” and “auto” are not default specifiers applied to declarations the way it says. The effects of
externdepend on where declarations appear and what prior declarations there are. A declarationint i;at file scope cannot be said to have a defaultexternspecifier becauseextern int i;has a different effect, discussed below.At file scope,
int i;is a tentative definition for an object namedi(C 2018 6.9.2 2). In spite of its name, a tentative definition is not a definition (just as a prospective employee on a job interview is not an employee). If no regular definition is present in a translation unit, a tentative definition will cause a definition to be created. However, because different C implementations treatedint i;differently, the C standard does not define what happens if there are multiple definitions (C 2018 6.9 5, C 2018 4 2). Some C implementations coalesce multiple definitions resulting from compatible tentative definitions into a single definition. Some treat them as an error. The default changed in GCC version 10.At file scope,
extern int i;is a declaration for an object namedithat is not a definition. It does not reserve storage fori, and, ifiis used in the program, there must be a definition for it somewhere else in the program. This declaration givesiexternal linkage unless a prior declaration is visible (see below).At file scope,
extern int i = 0;is a definition for an object namedi. According to the rules of the C standard, a declaration with an initialization is a definition, even if it hasextern, so a compiler should treat it as a definition. However, it is a convention of users of C not to useexternwith definitions. So declaringint iwithexternand also providing an initialization with= 0goes against that convention. But that is just a convention of users, not a rule of the C standard. So compilers will warn about this violation of convention, but a compiler that conforms to the C standard must accept this code as a definition ofi. (If you turn warnings into errors, as with the-Werrorswitch with Clang or GCC, the compiler does not accept this code and becomes a non-conforming compiler.)As an example of another complication, if
extern int i;appears where a prior declaration ofiasstatic int i;is visible, the linkage ofiatextern int i;is internal, not external (C 2018 6.2.2 4). The rules forexterncannot be stated as “It makes the linkage external” or even “At file scope, it makes the linkage external.” Its effects depend both on its scope and on prior declarations, using multiple rules stated in different places in the C standard.