[转]C/C++关于全局变量和局部变量初始化与不初始化的区别

原文链接:http://www.kingofcoders.com/viewNews.php?type=newsCpp&id=189&number=4836955386

在C语言里,全局变量如果不初始化的话,默认为0,也就是说在全局空间里:int x =0; 跟 int x; 的效果看起来是一样的。但其实这里面的差别很大,强烈建议大家所有的全局变量都要初始化,他们的主要差别如下:

编译器在编译的时候针对这两种情况会产生两种符号放在目标文件的符号表中,对于初始化的,叫强符号,未初始化的,叫弱符号。连接器在连接目标文件的时候,如果遇到两个重名符号,会有以下处理规则:

1、如果有多个重名的强符号,则报错。

2、如果有一个强符号,多个弱符号,则以强符号为准。

3、如果没有强符号,但有多个重名的弱符号,则任选一个弱符号。

    大部分情况下,我们不希望连接器为我们做决定,所以我不是很认同后两个规则,至少应该给个警告,而不应该安静地通过。因为这种问题引起的bug会很难查,所以我们要尽量把全局变量初始化,对于不想给别的文件引用的变量,也尽量用static修饰。除了连接时的表现不一样外,未初始化的符号在目标文件的bss段中,而初始化的符号在data段中。

注: bss段(未手动初始化的数据)并不给该段的数据分配空间,只是记录数据所需空间的大小。
        data段(已手动
初始化的数据)则为数据分配空间,数据保存在目标文件中。

对于局部变量,不被初始化的话,其值一般分为两种情况Debug版和Release版的区别。

例:

#include "stdafx.h"
int i;
int main(int argc, char* argv[])
{
printf(" i = %d\n",i);
int j;
printf(" j= %d\n",j);
return 0;
}

在Debug版下,在这段代码中i的值打印出来是0,而j的值打印出来是-858993460,也就是0xCCCCCCCC.至于为什么是这个值,有网友给出这个解释。(设计成0xcccccccc是有特殊用意的……这个好像叫做Poison,未初始化的Pointer去取值的话会出错。肯定有人问为什么不弄成0x00000000,因为空指针是指针的有效状态,可能会误导人,而0xCCCCCCCC在Windows下永远不可能是一个指针的有效状态(不是NULL,不指向一个对象,不指向一堆对象紧接之后的区域),这就是在模拟野指针……)。

值得注意的是,同样的代码在Release版下,这段代码中未被初始化的变量最后打印出来的可能都是0。也有强大的网友给出解释。(重点在于vc的一个功能:Catch release-build errors in debug build用/GZ编译开关打开。debug版这个开关是开的,release版是关的(为了效率)。这个开关说白了就是把所有动态局部变量初始化成0xcccccccc,把所有动态堆变量初始化成0xcdcdcdcd。很多新手会忘记初始化这些本来应该初始化的变量(尤其是new出来的变量),有时他们会假定这些变量应该是0,这样就可能出现在release版正常而debug版不正常的程序,因为release版至少局部变量的初始值很可能就是0,而有时他们又会假定或者期望这些变量不是0,这样就带了一个最难发现的bug)。

鉴于上面分析,建议大家养成初始化一个变量的习惯。

posted @ 2014-09-18 16:22  Andy Cheung  阅读(1070)  评论(0编辑  收藏  举报