External linkage of const in C

2019-06-09 17:18发布

问题:

I was playing with extern keyword in C when I encountered this strange behaviour. I have two files:

file1.c

#include<stdio.h>
int main()
{
    extern int a;
    a=10;
    printf("%d",a);
    return 0;
}

file2.c

const int a=100;

When I compile these files together, there is no error or warning and when I run them, output comes to be 10. I had expected that the compiler should report an error on line a=10;.

Moreover, if I change the contents of file2.c to

const int a;

that is, if I remove the initialization of global const variable a and then compile the files, there is still no error or warning but when I run them, Segmentation Fault occurs.

Why does this phenomenon happen? Is it classified under undefined behaviour? Is this compiler- or machine- dependent?

PS: I have seen many questions related to this one, but either they are for C++ or they discuss extern only.

回答1:

Compilation and linking are two distinct phases. During compilation, individual files are being compiled into object files. Compiler will find both file1.c and file2.c being internally consistent. During linking phase, the linker will just point all the occurrence of the variable a to the same memory location. This is the reason you do not see any compilation or linker error.

To avoid exactly the problem which you have mentioned, it is suggested to put the extern in a header file and then include that header file in different C file. This way compiler can catch any inconsistency between the header and the C file

The following stackoverflow also speaks about linker not able to do type checking for extern variables.

Is there any type checking in C or C++ linkers?

Similarly, the types of global variables (and static members of classes and so on) aren't checked by the linker, so if you declare extern int test; in one translation unit and define float test; in another, you'll get bad results.



回答2:

It is undefined behaviour but the compiler won't warn you. How could it? It has no idea how you declare a variable in another file.

Attempting to modify a variable declared const is undefined behaviour. It is possible (but not necessary) that the variable will be stored in read-only memory.



回答3:

This is a known behavior of C compilers. It is one of the differences between C and C++ where strong compile time type checking is enforced. The segmentation fault occurs when trying to assign a value to a const, because the linker puts the const values in a read-only elf segment and writing to this memory address is a runtime (segmentation) fault. but during compile time, the compiler does not check any "externs", and the C linker, does not test types. therefore it passes compilation/linkage.



回答4:

Your program causes undefined behaviour with no diagnostic required (whether or not const int a has an initializer). The relevant text in C11 is 6.2.7/2:

All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.

Also 6.2.2/2:

In the set of translation units and libraries that constitutes an entire program, each declaration of a particular identifier with external linkage denotes the same object or function.

In C, const int a = 100; means that a has external linkage. So it denotes the same object as extern int a;. However those two declarations have incompatible type (int is not compatible with const int, see 6.7.2 for the definition of "compatible type").