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;
。 但是这两个声明具有不兼容的类型( int
与const int
不兼容,有关“兼容类型”的定义,请参见6.7.2)。