C中const的外部链接

当我遇到这种奇怪的行为时,我正在使用C中的 extern关键字。 我有两个文件:

在file1.c

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

file2.c中

 const int a=100; 

当我一起编译这些文件时,没有错误或警告,当我运行它们时,输出变为10 。 我原以为编译器应该在a=10;行报告错误a=10;

此外,如果我将file2.c的内容更改为

 const int a; 

也就是说,如果我删除全局const变量a的初始化然后编译文件,仍然没有错误或警告,但是当我运行它们时,会发生分段错误。

为什么会出现这种现象? 它是否归入未定义的行为? 这是编译器还是机器依赖的?

PS:我看过很多与此问题相关的问题,但要么是C ++,要么只讨论extern

编译和链接是两个不同的阶段。 在编译期间,单个文件正在编译为目标文件。 编译器会发现file1.c和file2.c在内部是一致的。 在链接阶段,链接器只会将变量a所有出现指向同一个内存位置。 这是您没有看到任何编译或链接器错误的原因。

为了避免您提到的问题,建议将extern放在头文件中,然后将该头文件包含在不同的C文件中。 这样编译器可以捕获标头和C文件之间的任何不一致

以下stackoverflow还说明了链接器无法对extern变量进行类型检查。

在C或C ++链接器中是否有任何类型检查?

类似地,链接器不检查全局变量的类型(以及类的静态成员等),因此如果声明extern int test; 在一个翻译单元中定义浮动测试; 在另一个方面,你会得到不好的结果。

它是未定义的行为,但编译器不会警告您。 怎么可能? 它不知道你如何在另一个文件中声明一个变量。

尝试修改声明为const的变量是未定义的行为。 变量可能(但不是必须)存储在只读存储器中。

这是C编译器的已知行为。 它是C和C ++之间的差异之一,强制执行强编译时类型检查。 尝试将值分配给const时会发生分段错误,因为链接器将const值放在只读精灵段中,并且写入此内存地址是运行时(分段)错误。 但在编译期间,编译器不会检查任何“externs”,而C链接器也不会测试类型。 因此它通过编译/链接。

您的程序导致未定义的行为,无需诊断( const int a是否具有初始化程序)。 C11中的相关文本是6.2.7 / 2:

引用同一对象或函数的所有声明都应具有兼容类型; 否则,行为未定义。

另外6.2.2 / 2:

在构成整个程序的翻译单元和库的集合中,具有外部链接的特定标识符的每个声明表示相同的对象或function。

在C中, const int a = 100; 意味着a具有外部链接。 所以它表示与extern int a;相同的对象extern int a; 。 但是这两个声明具有不兼容的类型( intconst int不兼容,有关“兼容类型”的定义,请参见6.7.2)。