当我遇到这种奇怪的行为时,我在C 中玩extern
个关键字。
我有两个文件:
file1.c中
#include<stdio.h>
int main()
{
extern int a;
a=10;
printf("%d",a);
return 0;
}
file2.c中
const int a=100;
当我一起编译这些文件时,没有错误或警告,当我运行它们时,输出变为10
。我曾预料到编译器应该在行a=10;
上报告错误。
此外,如果我将file2.c的内容更改为
const int a;
也就是说,如果我删除全局const变量a
的初始化然后编译文件,仍然没有错误或警告,但是当我运行它们时,会出现Segmentation Fault。
为什么会出现这种现象?它是否归入未定义的行为?这是编译器还是机器依赖的?
PS:我看过很多与此问题相关的问题,但要么是针对C ++,要么只讨论extern
。
答案 0 :(得分:1)
编译和链接是两个不同的阶段。在编译期间,单个文件正在编译为目标文件。编译器会发现file1.c和file2.c在内部是一致的。在链接阶段,链接器只会将变量a
的所有出现指向同一个内存位置。这是您没有看到任何编译或链接器错误的原因。
为了避免您提到的问题,建议将extern放在头文件中,然后将该头文件包含在不同的C文件中。这样编译器可以捕获标头和C文件之间的任何不一致
以下stackoverflow还谈到链接器无法对外部变量进行类型检查。
Is there any type checking in C or C++ linkers?
类似地,链接器不检查全局变量的类型(以及类的静态成员等),因此如果声明extern int test;在一个翻译单元中定义浮动测试;在另一个方面,你会得到不好的结果。
答案 1 :(得分:0)
这是未定义的行为,但编译器不会警告您。怎么可能呢?它不知道如何在另一个文件中声明变量。
尝试修改声明为const
的变量是未定义的行为。可以(但不是必须)将变量存储在只读存储器中。
答案 2 :(得分:0)
这是C编译器的已知行为。它是C和C ++之间的差异之一,强制执行强编译时类型检查。 尝试将值分配给const时会发生分段错误,因为链接器将const值放在只读精灵段中,写入此内存地址是运行时(分段)错误。 但是在编译期间,编译器不检查任何&#34; externs&#34;,而C链接器不测试类型。因此它通过编译/链接。
答案 3 :(得分:0)
您的程序会导致未定义的行为,无需诊断(const int a
是否具有初始值设定项)。 C11中的相关文本是6.2.7 / 2:
引用同一对象或函数的所有声明都应具有兼容类型;否则,行为未定义。
另外6.2.2 / 2:
在构成整个程序的翻译单元和库的集合中,具有外部链接的特定标识符的每个声明表示相同的对象或功能。
在C中,const int a = 100;
表示a
具有外部链接。因此它表示与extern int a;
相同的对象。但是这两个声明的类型不兼容(int
与const int
不兼容,请参阅6.7.2以了解&#34;兼容类型&#34;)。