4

Following are the two separate codes written in two separate files Test1.c and Test2.c. I am not using extern keyword in any file.

//Test1.c
#include <stdio.h>

int a = 1;
int main()
{
    printf("test1 - a val = %d\n",a);
    fn();
    printf("After Return : %d",a);
}

//Test2.c
#include <stdio.h>

int a;
int fn()
{
    printf("test2 - a val = %d\n",a);
    a++;
}

I compiled this code using gcc:

gcc Test1.c Test2.c

It generates the following output:

test1 - a val = 1
test2 - a val = 1

I tried printing address of variable a in both codes. The address is also same.

Now I have following questions:

  1. Does gcc automatically compile and link even if extern is not used?? Here apparently gcc internally does that as I am compiling these two files together.
  2. Is this behaviour with/without extern keyword is compiler-dependent?
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
sandeep.ganage
  • 1,409
  • 2
  • 21
  • 47
  • It isn't strictly compliant C. It is a 'common extension' documented in Annex J of the standard. See also the section 'Not so good way to define global variables' in [How do I use `extern` to share variables between source files in C?](http://stackoverflow.com/questions/1433204/) – Jonathan Leffler Jan 12 '17 at 06:54
  • Compile with `-fno-common` option. – Sourav Ghosh Jan 12 '17 at 07:04
  • @JonathanLeffler How can this be duplicate of that question? My question was regarding behaviour of extern with gcc compiler. – sandeep.ganage Jan 12 '17 at 07:20
  • 1
    It is asking about the behaviour of `extern` and not-`extern` which is covered in the other question. What you're seeing is one common pattern of behaviour. It is sanctioned by the standard as an extension, but it is not strictly conforming to the letter of the standard (Annex J is 'informative' and not 'normative'). What GCC does is covered by the duplicate question, without calling out GCC by name. If you find other people to reopen the question, I won't contest it, but I think it's a fair duplicate decision. – Jonathan Leffler Jan 12 '17 at 07:46

1 Answers1

4

This code is undefined behaviour with no diagnostic required. Test1.c and Test2.c both define an object a with external linkage, which violates C11 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; otherwise, there shall be no more than one.

Note: "external definition" means a definition at file scope. (C11 6.9/4, 6.9/5). Some other comments/answers confuse "external definition" with "definition of object with external linkage", or "definition with extern keyword". static int x = 5; at file scope is an external definition.


As mentioned by Jonathan Leffler in comments, this particular result may be an intentional GCC extension. From C11 Annex J.5.11 "Common extensions" :

There may be more than one external definition for the identifier of an object, with or without the explicit use of the keyword extern; if the definitions disagree, or more than one is initialized, the behavior is undefined.

If gcc implements this extension then it would explain the behaviour you observed. Presumably "more than one is initialized" in that quote does not count the implicit initializer generated for a tentative definition.

M.M
  • 138,810
  • 21
  • 208
  • 365