-
Notifications
You must be signed in to change notification settings - Fork 2
Description
In CI here, clang complained of a double definition.
This looks like a valid complaint to me, though as we saw here, gcc successfully compiles the same code. Presumably this means the code is incorrect (i.e. compiler behavior is unspecified) but gcc is being lenient in some way.
Quoting @giordano:
maybe the issue is that the global variable in the header file is being defined twice in two different object files. It's just a completely bad idea to define variables in header files (without being extern at least).
I've personally never seen an issue like this before, for (I think) two reasons: (1) I've never seen a non-static
, non-extern
global variable in a header file; (2) all the codebases I've worked in have had include guards on the header files, so re-declaration was not happening.
What we need to do
We should fix the link error in a way that does not change program behavior.
As far as I can see, the only sane way this program would compile is if the offending line is being treated as an extern
declaration. However I don't have iron-clad proof of this, and I think it's a statement about the behavior of GCC that is not mandated by the C standard.
Of course, we could also start reasoning about the program itself and what it's supposed to do, and/or contact the author 🙂
Attempting to get a full explanation
According to Wikipedia:
If neither the extern keyword nor an initialization value are present, the statement can be either a declaration or a definition. It is up to the compiler to analyse the modules of the program and decide.
According to cppreference
For objects, a declaration that allocates storage (automatic or static, but not extern) is a definition, while a declaration that does not allocate storage (external declaration) is not.
extern int n; // declaration int n = 10; // definition
Sadly, the above quote does not explicitly say whether the statement
int n;
with no storage-class specifier and no initialization must be considered a definition, or must be considered only a declaration, or whether it's up to the toolchain. (Wikipedia apparently says it's up to the toolchain.)
As far as I can tell, this line is getting inlined twice by the preprocessor (since there is no include guard), and the clang error above seems to indicate that clang is considering at least two of the copies of that line to be definitions (since the only other use of that name in the codebase is definitely neither a definition nor a declaration). Perhaps gcc chooses not to consider more than one of those copies a definition.
On the other hand, if all copies of that line are considered to be declarations and not definitions, then the following excerpt from cppreference:
If no storage-class specifier is provided, the defaults are:
extern
for all functionsextern
for objects at file scopeauto
for objects at block scope
implies that the line is equivalent to
extern long FirstTime;