My simple-mind understanding of "extern" is that the compiler just needs to allocate that space, and the linker will resolve it at link time. It suppresses the "undefined symbol" warning. It probably also prevents the variable from being optimised-out if not used for any "final" purpose.
I'm not saying this is wrong, but... how weird way of thinking.
But I understand the confusion, there are many poor choices for reserved words in C; for example "extern", "static", etc. "extern" gives you an idea this is something about something being
external, but this is not the case at all. The keyword controls the difference between declaration and definition.
The "extern" keyword just means you are
declaring a variable or function: telling the compiler the important meta information such as
type and type qualifiers; and of course, the fact that it
exists. Memory is never reserved for it.
When you leave out "extern" keyword, then whatever you write becomes both a declaration and definition. Of course if you already have a declaration earlier, the types and qualifiers must exactly match.
It should be really this simple. It's made a bit confusing by the fact that
type func(); <-- note the ;
automatically works like there was
extern written here, even if you omit it - i.e., declaration only. The idea was probably to save some typing time; compiler can figure out from the lack of function body that this can only be a declaration.
Another confusing thing are the "tentative definitions". Better just forget this part, and follow the logical and least confusing way:
* Explicit, clear
declarations in header files, which are included wherever needed. This means
extern keyword on all variables. It's matter of taste if you use
extern on function declarations or leave it out. Doesn't affect the result.
* Exactly one definition in exactly one compilation unit, in a .c file.
Of course, if only a single .c file uses a function or a variable, and you know others never need it, then you make that function or variable
static (another confusing keyword; really controls if the thing is exposed to the outside world or not), and do
not add a declaration in .h. Most of the functions and variables usually are this way (which also makes one think, the
static works the wrong way; the default behavior should be an "internal" function or variable, with a PUBLIC keyword or similar. But oh well, C is like this. At least the functionality is there! You just need to know how to use it.)
TLDR:
module1.h
#pragma once
extern int public_int;
extern void public_func(); // extern can be omitted here
module1.c
#include "module1.h"
int public_int;
static int private_int;
void public_func() {
...
}
static void private_func() {
...
}