The following snippet works fine
extern int i;
int i;
int main(){
return 0;
}
Here what I got is, 'i' is declared and then defined. Since there is only one definition so thats perfectly fine.
int main(){
extern int i;
int i;
return 0;
}
Now, the above one gives the following error
new.cpp: In function ‘int main()’:
new.cpp:5:6: error: redeclaration of ‘int i’
int i;
^
new.cpp:4:13: note: previous declaration ‘int i’
extern int i;
Whats the problem here? Here also there is single definition of 'i'.
To understand the difference, you need to get familiar with a concept called tentative definition in C. To quote the C standard:
C11, draft, §6.9.2, External object definitions
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.
What you have in the first snippet is only a tentative definition for i
. You can have as many tentative definitions for an object as you want (but only one definition is allowed):
int i; // tentative definition
int i; // tentative definition
int i; // tentative definition
int main(void) {
return 0;
}
is valid.
Here, i
has external linkage and tentatively defined. If i
is defined in somewhere in the same translation unit, then that'll be the actual definition of i
. If there's no other definition of i
is found in the translation unit, then this becomes the full definition as if it was defined like:
int i = 0;
int main(void) {
return 0;
}
But the second snippet int i;
is not a tentative definition. Only objects with external linkage can be defined tentatively. In second snippet, The declaration extern int i;
says i
is defined elsewhere with external linkage. But the next line int i;
says i
is defined with no linkage (local automatic variables do not have any linkage -- this is not a tentative definition). So there's a conflict of definition for i
. Hence, the first one snippet is fine but second isn't.
In the second case, there are two declarations of i
in one scope. One says "there is a variable i
defined outside this function"; the other says "there is a variable i
defined inside this function". Without a new scope, that isn't allowed.
The rules are different inside and outside functions.
Note that you could use:
#include <stdio.h>
int i = 21;
int main(void)
{
extern int i;
i = 37;
{
int i = 57;
printf("%d\n", i);
}
printf("%d\n", i);
return 0;
}
This compiles OK (unless you include -Wshadow
in your compilation options when using GCC or Clang), and produces 57
and 37
on the output (as pointed out by CoffeeAndCode in a comment).
See also How do I use extern
to share variables between source files?