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.
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.
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.
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.
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").