c中的初始化vs未初始化的全局const变量

时间:2014-08-07 09:50:35

标签: c

对不起,我不太善于解释问题。所以我直接从例子开始

请看以下示例

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)。

3 个答案:

答案 0 :(得分:8)

您正在修改一个const对象,而这只是undefined behavior - 所以不要这样做,不要忽略编译器警告。

现在,在您的特定情况下,不同行为的实际原因是,对于const int a=10;,值10必须存储在某处。由于变量是const,链接器将它放在.rodata或可执行文件的类似只读部分。当您尝试写入只读位置时,您将遇到分段错误。

对于未初始化的案例const int aa需要初始化为零,因为它在文件范围(或a是全局变量)。然后,链接器将变量放在.bss部分中,以及在程序启动时也初始化为零的其他数据。 .bss部分是可读/写的,当你尝试写入时,你不会得到段错误。

所有这些都不是你可以依赖的东西,如果你使用另一个编译器或更新版本的编译器等,这可能会随着对代码的微小修改而改变。

答案 1 :(得分:5)

如果您的代码没有按照C标准的要求明确地执行,则隐式初始化全局变量和静态变量。

来自doc:

  

const是一个类型限定符。另一种类型限定符是volatile。该   const的目的是宣布可能放入的对象   只读内存,也许是为了增加机会   优化

在G ++中,您将收到第二种情况的错误,即const int a;

  

6.9.2外部对象定义

     

<强>语义

     

1如果对象的标识符声明具有文件范围和   一个初始化器,声明是一个外部定义   标识符

     

2具有文件范围的对象的标识符声明   没有初始化程序,没有存储类说明符或没有   存储类说明符静态,构成一个暂定的   定义。如果翻译单元包含一个或多个暂定单元   标识符的定义,翻译单元包含否   该标识符的外部定义,然后行为是完全正确的   好像翻译单元包含一个文件范围声明   标识符,在翻译结束时使用复合类型   单位,初始化程序等于0。

答案 2 :(得分:0)

声明一个常量整数变量。这意味着它的价值无法修改。它的值最初分配给10。 如果您稍后尝试更改其值,编译器将发出警告或错误,具体取决于您的编译器设置。