记一件有意思的事

写生活日志么?想都别想:)

这件事跟未初始化的非静态局部变量的值有关。

通常,作为一个合格的程序员,定义变量都会给它初始化,特别是非静态的局部变量,使用未初始化的非静态局部变量会发生错误。然而,喵哥今天在看书的时候遇到这么一个奇葩的例子:

#include <bits/stdc++.h>
using namespace std;

int global_init_var = 0;
__attribute__((section("foo")))  int global_uninit_var;

void func1(int i){
    printf("%d\n", i);
}

int main(){
    static int static_var = 85;
    static int static_var2;
    int a = 1;
    int b;    //没有初始化
    func1(static_var + static_var2 + a +b);
    return 0;
}

看到这代码第一反应就是这代码是不是错了,然后喵哥本着“实践是检验真理的唯一标准”的精神,把上面的代码码了下来,然后跑了一下

我惊了,居然顺利运行过了。本以为由于b没有初始化而得到一个非法的值,但是用GCC跑出来的b老老实实的默认为0

有点颠覆三观了,跟平时完全不是一回事,然后想到这会不会跟用的编译器有关,我这里用的是GCC。特意去windows用VS跑了一遍,幸好出错了

这是在debug的模式下跑的,b被赋值为0xcccc cccc,并发生异常中断。

如果是release下跑,则不会报异常中断,但是运行结果是错的。

这说明需要要对非静态局部变量初始化不是错觉,平常也需要这么做。

并且,用clang编译得到的结果也是不对的:

那么为什么GCC会给它赋值为0呢,这大概就是底层编译器底层实现的区别了,在网上看到这么一段话:


引自百度知道:gcc局部变量不用初始化么
以 C99 标准为例:

6.7.8/10 未显式初始化的非静态局部变量的值是「不定的」。

3.17.2 「不定的值」是「未指定的值」或「陷阱标识」。

3.17.3 「未指定的值」是该类型有效值,但本国际标准对于具体选择哪个值不作要求。

6.2.6.1/5 对值为「陷阱标识」的对象进行读操作是未定义行为。

所以,这种代码有可能触发未定义行为,能不能跑全靠运气。即便不触发,取值是多少也没有标准保障。


GCC应该是默认把为初始化的整数值初始化为0吧,在喵哥看的那本书中也的确经常提到未初始化与初始化为0 的隐晦关系。比如:

经过初始化的全局变量和静态局部变量会保存在.data处,对于没有初始化的全局变量和静态局部变量则会保存在.bss处,但是如果全局变量和静态局部变量初始化为0的话,则这些全局变量和静态局部变量也会保存在.bss处。

这么说来GCC中对于这个“不定值”的定义可能就是0吧。


2019.07.20

用clang编译的没有初始化的全局变量和静态局部变量和初始化为0的全局变量和静态局部变量也保存在.bss处,所以这个关系跟非静态局部变量初始化为0没啥关系了。。。

发布了55 篇原创文章 · 获赞 29 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/ruibin_cao/article/details/96506795