Reputation:
I have the following program in two files:
a.c
#include<stdio.h>
#include"b.c"
int main(void){
extern int a;
a+=2;
printf("%d\n",a);
return 0;
}
b.c
int a=1;
Now I use the extern keyword to declare the variable a, but not define it. Hence, I can change its contents, and printing it will print 3.
What I don't understand is that if I remove the line extern int a;
from a.c, the program runs as well and the output is still 3.
I thought that to change the variable in b.c, you had to use the extern keyword.
What is happening here?
Upvotes: 1
Views: 131
Reputation: 1775
Take this program for example:
#include<stdio.h>
void main()
{
extern int y;
printf("%d",y);
}
int y=10;
The output looks like this:
10
extern
is a declaration, not (necessarily) a definition.
When used by itself, extern
does not define a variable, meaning it does not assign a memory address to it. It only declares the variable so you can use it.
In your example, you did not have to declare a
for the simple reason that it had already been defined.
On the other hand, if the extern
variable is immediately assigned to something, it will ALSO define it. (Thanks, @John Bollinger)
extern int b=20;
The #include
directive does not define a logical scope.
In a simple (and correct) understanding, #include
copy pastes the code from one file into the one you are trying to run. That means that if you removed the extern
statement, there wouldn't be a problem since a
had already been defined by int a=1;
. Think of it as just using a global variable normally.
On the other hand, if you move
#include"b.c"
to the bottom of your program, you would need that extern
statement. Without it, the compiler wouldn't know that y
will be defined at some point. This statement tells the compiler to search for the declaration before sending an error telling you the variable doesn't exist.
Upvotes: 2
Reputation: 224546
When the compiler is compiling the main
routine, it has already seen the int a=1;
in the b.c
you included, so extern int a;
does not tell it anything new. Therefore it does not do anything.
extern int a;
says “a
is a name for an int
, and that int
is defined somewhere else.” However, by including b.c
, you included int a=1;
, which defines a
. So the compiler already knows a
is defined as an int
.
I thought that to change the variable in b.c, you had to use the extern keyword.
To refer to an object by name, you need to provide a declaration of that name. The int a=1;
that you included is a declaration (and it is a definition).
You do not need extern
to say I will refer to an object by name, but you do need it to say “I am not defining the object here, just telling you about an object that is defined somewhere.” The proper way to use it is not to include b.c
in a.c
but rather:
b.c
, define a
with int a=1;
.b.h
, declare a
with extern int a;
.a.c
, use #include "b.h"
to include the declaration.a.c
, you do not need to write extern int a;
yourself because you get that when you include b.h
.b.c
, use #include "b.h"
to check the declaration. (When you include b.h
in b.c
, the compiler will see both the declaration and the definition during the same compilation, and it will warn if there is a mistake that makes the declarations conflict.)Upvotes: 0
Reputation: 68034
In the fact you are compiling:
#include<stdio.h>
int a = 1;
int main(void){
extern int a;
a+=2;
printf("%d\n",a);
return 0;
}
You have only one compilation unit and a
is not defined in another compilation unit.
When you remove the extern
from the declaration you define not initialized local automatic variable a
. Then you use it and it has undeterminable value. It can be anything.
#include<stdio.h>
int a = 5;
int main(void){
int a;
a+=2;
printf("%d\n",a);
return 0;
}
It is very unlikely this program to output 7
: https://godbolt.org/z/GeGvbd
Upvotes: 1