Search code examples
coutputexternstorage-class-specifier

Extern in multiple files and possible double definition


I was running the following codes compiled together as: gcc A.c B.c -o combined

Program A:

#include<stdio.h>
int a=1;
int b;
int main()
{
extern int a,b;
fun();
printf("%d %d\n",a,b);
}

Program B:

int a;
int b=2;
int fun()
{
printf("%d %d\n",a,b); 
return 0;
}

On running the "combined" program the output was:

1 2
1 2

Now, I've a few doubts about this one:

  1. Why isn't the output:

    0 2

    1 0

  2. Aren't a and b defined twice?

Please explain these clearly, I've had a lot of problems understanding extern and few of these doubts keep coming from time to time.

Thanks in Advance.


Solution

  • So, I am answering my own question after a long time. Although the statement:

    int b; is a decalaration and int b = 2; is the definition

    is correct but the reason everyone is giving is not clear.

    Had there not been a int b = 2;, int b; was a definition, so what is the difference?

    The difference lies in the way the linker handles multiple symbol definitions. There is a concept of weak and strong symbols.

    The assembler encodes this information implicitly in the symbol table of the relocatable object file. Functions and initialized global variables get strong symbols. Uninitialized global variables get weak symbols.

    So in Program A, int a = 1 is a strong symbol while int b; is a weak symbol, similarly in Program B, int b = 2 is a strong symbol and while int a is weak.

    Given this notion of strong and weak symbols, Unix linkers use the following rules for dealing with multiply defined symbols:

    1. Multiple strong symbols are not allowed.
    2. Given a strong symbol and multiple weak symbols, choose the strong symbol.
    3. Given multiple weak symbols, choose any of the weak symbols.

    So, now we can argue about what is happening in the above case.

    1. Among int b = 2 and int b, the former is a strong symbol while the latter is weak so b is defined with value 2.
    2. Among int a = 1 and int a, a is defined as 1 (same reasoning).

    Hence, the output 1 2.