Search code examples
ctype-conversionextern

Extern declaration and definition type difference


There was a question in our class about what will happen if we declare a variable as extern long in a .c file and then define that variable as double in another.c file.

When we tried to print the long variable we obviously got a garbage value or overflow value, I am not sure (i.e. It was some negative value — the same in everyone's device so probably not just a garbage value).

I want to understand what's going on inside the compiler and linker when we do this. And how the memory for the variable ends up having a garbage value or overflow value. We also wanted to get the integer part of the variable defined as a double. Is there any way to do that without matching the extern declaration and definition type of the variable.

The a.c file

#include<stdio.h>
extern long x;

int main(){
    printf("%ld", x);
    return 0;
}

The b.c file

double x = 3.1456;

Solution

  • As everybody says, this is undefined behaviour - the compiler is allowed to do anything. In reality, what is happening (probably, assuming a mainstream toolchain) is that, when the compiler compiles b.c it reserves probably eight bytes for the double representation of 3.1456, which, assuming IEEE double precision and a little endian platform is.

    7c 61 32 55 30 2a 09 40
    

    (bytes above are in hex)

    When the compiler comes to compile a.c it assumes x is long and will treat it as such but will not allocate any space for it. It uses a placeholder address instead. The linker will then replace any occurrences of the placeholder with the real address from b.c

    If the compiler has an eight byte long, it will interpret that as 0x40092a305532617c. If it has a four byte long, it will interpret it as 0x5532617c.

    Note that there are lots of caveats to the above depending on compiler implementation and the architecture. This is why it's undefined behaviour. It's easier to let implementers handle it how they want than to enforce some particular behaviour, even emitting an error diagnostic.

    We also wanted to get the integer part of the variable defined as a double. Is there any way to do that without matching the extern declaration and definition type of the variable.

    Simply casting a double to an int will get the integer part assuming all the bits fit in an int (if int is 32 bits and double is an IEEE double precision, the mantissa is 52 bits, which won't always fit).

    // in b.c
     printf("%d\n", (int) x); // Prints 3