When you place the line extern int x;
in your extern.h
file, what you're stating is that there exists an x
somewhere but not here (well, not here unless you also have an int x;
as well in the same scope).
In other words, it's a declaration that something exists rather than a definition that creates that something. So, without a definition, that particular x
is never created.
In both your foo1()
and foo2()
functions, you do create something called x
, however it's not the same x
as the one you've declared in extern.h
: it has different scope.
Both the x
in foo1()
and foo2()
(and they are distinct variables, not the same one) are local to the function they're defined in. Hence foo1()
creates its x
, sets the value of it to 200
then throws that away on exit.
foo2()
, on the other hand, creates its x
with an arbitrary value and then prints it (hence your "junk value" comment).
That explains the behaviour you're seeing, now how to fix that. The way this is normally done is to define the variable somewhere (only once) and declare it wherever it's used, something like:
extern.h:
extern int x; // declare it
void foo1(void);
void foo2(void);
foo1.c:
#include "extern.h" // declare x via the header
void foo1(void) {
x = 200; // set x, note: no int at start of line
// since that would create a NEW x.
}
foo2.c:
#include <stdio.h>
#include "extern.h" // declare x via the header
void foo2(void) {
printf "%d\n", x); // again, no "int x;" since that would
// create a NEW x.
}
main.c:
#include "extern.h" // declare in the header
int x; // and define it.
int main (void) {
foo1();
foo2();
return 0;
}
So the "global" x
exists in main.c
(though you could put it in any of the C files, as long as it's only in one of them). The fact that both foo1.c
and foo2.c
include the extern.h
header that declares the existence of x
means that they'll be able to find it.
By ensuring that neither foo1()
nor foo2()
define another x
in local scope (by using int x;
or int x = something;
), they'll use the x
at the next outer scope (i.e, the one in main.c
).
When you define an inner-scope variable of the same name as an outer scope one, the former "hides" (or "shadows") the latter. For example, the code:
#include <stdio.h>
int main (void) {
int x = 42;
printf ("A: %8d\n", x);
{
int x = 314159;
printf ("B: %8d\n", x);
}
printf ("C: %8d\n", x);
return 0;
}
will output:
A: 42
B: 314159
C: 42
as the inner braces create a new x
within that scope. And, when the scope ends, the x
you see then is the original one.