Search code examples
cgccextern

Why is there no error for a multiple definition of variable in the below C code?


I have two 2 files:

a.c:

#include <stdio.h>

extern int i = 5;

int main(){
    prnt();
}

b.c:

#include <stdio.h>

int i;

void prnt(){
    printf("%d",i);
}

The programs compile when linked together using gcc a.c b.c. The output obtained is 5. Shouldn't the gcc compiler give an error saying multiple definiton of i because in a.c, the variable i is both declared and defined and in b.c, the statement int i; is known to implicitly define the value to 0 with a hidden extern?


Solution

  • Firstly, to avoid confusion, extern int i = 5; is exactly the same as int i = 5;. It is a definition because of C11 6.9.2/1:

    If the declaration of an identifier for an object has file scope and an initializer, the declaration is an external definition for the identifier.

    (Note that "external definition" here means a definition at file scope - not to be confused with "external linkage").

    int i; is called a tentative definition ; in this case it behaves the same as int i = 0; (this is defined by 6.9.2/2), confirming that it is a definition. It has external linkage because of 6.2.2/5:

    If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.

    So both of those definitions define i with external linkage. Section 6.2.2/2 of the C standard says:

    [...] each declaration of a particular identifier with external linkage denotes the same object or function.

    So both of these i denote the same object.

    From 6.9/5:

    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

    Since you have provided two definitions for i , your program violates this rule, causing undefined behaviour with no diagnostic required.


    The reference for rule violation being undefined behaviour is 4/2:

    If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint or runtime-constraint is violated, the behavior is undefined.

    The quoted section from 6.9/5 is a "Semantic:", not a "Constraint:", so it counts as appearing outside of a constraint.