When compiled with g++ a.c b.c -Wall -O0
it produces a linking error, as expected. However, when invoking gcc a.c b.c -Wall -O0
it produces no warning and no error!
In your code, a
has a tentative definition (which becomes a full definition at the end of the current translation unit) which is valid in C.
However, there's another such tentative definition which becomes a full definition in b.c
from another translation unit—both of which provide an external definition for a
in your program. In other words, a.c
and b.c
are fine on their own, but it isn't valid when they are combined either compiling together (either directly you do or by compiling them into separate modules and then making an executable by linking them). This is undefined behaviour:
C11, 6.9/5:
An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof or _Alignof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.161
However, this is often supported as an extension by GCC. That's why when you invoke gcc
, it compiles fine as C code. Strictly (standard-wise), this is invalid code in C.
When you invoke g++
to compile it as C++ code, it'd fails because C++ has no tentative definitions. It's not valid in C++. Hence, g++
errors out. See One Definition Rule in C++.