对不起,我不太善于解释问题。所以我直接从例子开始
请看以下示例
const int a=10;
int *ptr;
int main(){
ptr=&a;
*ptr=100; // program crashes
printf("%d",a);
}
但如果我在上面的代码中略有改变,如下所示
const int a; // uninitialized global variable
然后上面的代码工作正常。
所以我的问题是为什么编译器对uninitialize和初始化全局const变量的行为不同?
我正在使用gcc for windows(mingw)。
答案 0 :(得分:8)
您正在修改一个const对象,而这只是undefined behavior - 所以不要这样做,不要忽略编译器警告。
现在,在您的特定情况下,不同行为的实际原因是,对于const int a=10;
,值10
必须存储在某处。由于变量是const,链接器将它放在.rodata或可执行文件的类似只读部分。当您尝试写入只读位置时,您将遇到分段错误。
对于未初始化的案例const int a
,a
需要初始化为零,因为它在文件范围(或a
是全局变量)。然后,链接器将变量放在.bss部分中,以及在程序启动时也初始化为零的其他数据。 .bss部分是可读/写的,当你尝试写入时,你不会得到段错误。
所有这些都不是你可以依赖的东西,如果你使用另一个编译器或更新版本的编译器等,这可能会随着对代码的微小修改而改变。
答案 1 :(得分:5)
如果您的代码没有按照C标准的要求明确地执行,则隐式初始化全局变量和静态变量。
来自doc:
const是一个类型限定符。另一种类型限定符是volatile。该 const的目的是宣布可能放入的对象 只读内存,也许是为了增加机会 优化
在G ++中,您将收到第二种情况的错误,即const int a;
。
6.9.2外部对象定义
<强>语义强>
1如果对象的标识符声明具有文件范围和 一个初始化器,声明是一个外部定义 标识符
2具有文件范围的对象的标识符声明 没有初始化程序,没有存储类说明符或没有 存储类说明符静态,构成一个暂定的 定义。如果翻译单元包含一个或多个暂定单元 标识符的定义,翻译单元包含否 该标识符的外部定义,然后行为是完全正确的 好像翻译单元包含一个文件范围声明 标识符,在翻译结束时使用复合类型 单位,初始化程序等于0。
答案 2 :(得分:0)
声明一个常量整数变量。这意味着它的价值无法修改。它的值最初分配给10。 如果您稍后尝试更改其值,编译器将发出警告或错误,具体取决于您的编译器设置。