Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC no warning or error when declaring a global variable multiple times [duplicate]

Tags:

c

gcc

Suppose the following code:

a.c:

#include <stdio.h>

int a;
int func();

int main(int argc, char **argv) {
a = 7;
int a2 = func();
printf("a is %d, a2 is %d\n", a, a2);
return 0;
}

and b.c:

int a;

int func()
{
a = 9;
return a;
}

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!

The output is a is 9, a2 is 9 by the way.

gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)

Why does GCC allow this? I was surprised by this behaviour. If you initialize the variables at declaration, then linking will also fail with GCC.

like image 547
user765269 Avatar asked Feb 15 '17 23:02

user765269


1 Answers

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 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 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++.

like image 150
P.P Avatar answered Oct 05 '22 23:10

P.P