Take this file as example,there are many non-extern structures like:
struct list_head source_list;
How can it work when this header file is included by more than one compile units?
There should be error reporting that the same symbol is defined twice,right?
Technically there should, but that usage has been around for years and is impossible to eradicate (it's been tried; every so often some vendor decides to make it an error, and reverts after the first hundred or so bug reports). Pedantically, the .h
file should declare it extern
and one .c
/.cpp
file should define it.
Briefly, when you don't specify the linkage (static
, extern
, etc.) of a top level variable, it's declared as "common". At link time, if all references to that variable are the same size (and type, when available) then it is allocated once and all references are made to point to it. If the linker finds different sizes / types / linkages for the same variable, it throws an error.
EDIT: this is clearly confounding people. Here:
jinx:1714 Z$ cat foo.h
int foo;
extern void bar();
jinx:1715 Z$ cat foo.c
#include "foo.h"
int
main(int argc, char **argv)
{
bar();
return 0;
}
jinx:1716 Z$ cat bar.c
#include "foo.h"
void
bar(void)
{
return;
}
jinx:1717 Z$ gcc -Wall foo.c bar.c -o foo
jinx:1718 Z$ ./foo
jinx:1719 Z$ _
Note the complete lack of errors about int foo
being multiply defined. This is what I've been trying to say.
The term for this is "tentative definition":
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.
So this is well defined in C (but often frowned upon).
This struct list_head source_list;
fields are declared inside other structures so they are not symbols.
Declarations of other (top level) structures have distinct names so it's ok too.
edit
Note that all variables it this header are really marked with extern
.
There should be an extern
indeed. However, there's no explicit definition of that variable, so the compiler marks it as extern for you.
You would get a linker error if you had
struct list_head source_list = { 0 };
...since this does define the symbol once per translation unit (and hence the linker complains).