xdavidliu
xdavidliu

Reputation: 3042

omission of extern for variable in C, but still works?

I am confused as why the following works:

test.c

#include <stdio.h>

int g;
// ??? should be extern int g; ??? 

int main(){
  printf("%i\n", g);
  return 0;
}

lib.c

int g = 3;

Why am I not getting a duplicate symbol error upon compilation? I get the error while trying to do this in C++, so that satisfies me. However, in this example, everything compiles and works (i.e. prints 3 successfully) whether or not I include extern. From reading all the other questions on StackOverflow about extern in C, everyone seems to be saying that extern used on a variable declares the variable but does not define (i.e. allocate memory) for it. But here, if I don't use extern, then I am defining two separate variables, both called g, so there should be some kind of duplicate symbol error. But there isn't, so I am very confused.

Upvotes: 1

Views: 166

Answers (1)

nalzok
nalzok

Reputation: 16107

N1570, 6.9.2 (Emphasis mine):

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

4 EXAMPLE 1

      int i1 = 1;                    // definition, external linkage
      static int i2 = 2;             // definition, internal linkage
      extern int i3 = 3;             // definition, external linkage
      int i4;                        // tentative definition, external linkage
      static int i5;                 // tentative definition, internal linkage
      int   i1;                      // valid tentative definition, refers to previous
      int   i2;                      // 6.2.2 renders undefined, linkage disagreement
      int   i3;                      // valid tentative definition, refers to previous
      int   i4;                      // valid tentative definition, refers to previous
      int   i5;                      // 6.2.2 renders undefined, linkage disagreement
      extern    int   i1;            // refers to previous, whose linkage is external
      extern    int   i2;            // refers to previous, whose linkage is internal
      extern    int   i3;            // refers to previous, whose linkage is external
      extern    int   i4;            // refers to previous, whose linkage is external
      extern    int   i5;            // refers to previous, whose linkage is internal

The int g; in your "test.c" is a tentative definition, giving g external linkage (See the examples). However, int g = 3; in "lib.c" has an initialiser, so it's not a tentative definition. As a result, the g in "test.c" refers to the g in "lib.c", whose value is initialised to 3.

See also: http://en.cppreference.com/w/c/language/extern

Upvotes: 1

Related Questions