Search code examples
ccastingdeclarationexternlinkage

Extern variable with different types in C


I was testing out scopes and visibility when I came across this situation I can't find an explanation for :

I have two .c files :

F1.c

#include <stdio.h>

void Modify();

int i;
int j;

int main()
{
  i=1;

  printf("i (main 1) = %d\n", i);

  Modify();

  printf("i (main 2) = %d\n", i);

  return 0;
}

and F2.c

#include <stdio.h>

extern char i [10];
extern int j;

void Modify()
{
  j=0;
  i[0]='a';
  i[1]= 'b';
  i[4]= 'e';

  printf("i (Modify) = %c\n", i[0]);
  printf("j (Modify) = %d\n", j);
}

When I compile and link them to create the executable that I Launch, here is the result :

i (main 1) = 1

i (Modify) = a

j (Modify) = 0

i (main 2) = 25185

What is happening? Does i changes types? Does giving an array with a size overpowers the declaration of i in F1.c?

Thanks!


Solution

  • This is against the rules of C. External globals need to have consistent declarations. (That's why we use headers to maintain the consistency.) You've given your toolset permission to make a mess of things.

    That being said, what's happening in your case is that the objects are simply overlaid (probably sufficient storage is being allocated for both int, and char[10], sort of like if there was a union there. If only 4 bytes are allocated (just for the int, not the array) then the i[4] access will overwrite something or less likely cause a segfault.).

    25185 is 0x6261, which assuming a little endian architecture corresponds to {0x61, 0x62, 0x00, 0x00}, i.e;, {'a', 'b', 0, 0 }. The 'e' isn't included in that number because your architecture's ints are 4 bytes large and the 'e' was put at the 5th byte.

    Again, you're in the realm of UB, so none of this is guaranteed behavior.