未初始化数组的值在块范围内被覆盖

Values of uninitialized array being overwritten in block scope

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[]) {
    int send_buf[4];
    if(1){
        int hello[5]={1,2,3,4,5};        
    }
    for(int i=0; i<4; ++i)
        printf("%d ",send_buf[i]);
    printf("\n");
    return 0;
}

输出: 1 2 3 4

在执行上述 C 代码时,输​​出总是导致分配给块范围内的数组 hello 的值。但是,如果在打印数组 send_buf 之前进行了任何引用(比如打印 send_buf 的地址),则输出结果通常是不确定的值。

有人可以解释一下为什么 send_buf 的内存已经分配到堆栈上时 send_buf 的值被覆盖了吗?

是否是某种 GCC 编译器优化延迟未初始化数组的分配直到它被引用?

使用 GCC 9.3.0 版编译。

当您不在 C 中(显式或隐式)初始化对象时,C 标准不保证它们具有任何固定值。它们的值可能会受到任何其他情况的影响,甚至可能会在每次使用时出现变化。

由于您没有初始化数组,编译器可能允许任何其他操作影响它。这可能包括允许 hello 的定义影响 send_buf 中出现的值。一个可能起作用的事实是编译器对值进行生命周期分析。例如,在如下代码中:

int p;
int q = 4;
printf("%d\n", q);
p = 3;
printf("%d\n", p);

编译器可能会发现,即使 p 是在 q 之前定义的,p 中永远不会同时有一个“活动”值,因为q,因此编译器可以为 q 使用与 p 相同的内存。同样,编译器可能已经决定 send_buf 永远不会与 hello 同时包含活动值,因此它可以为 hello 使用与 send_buf 相同的内存.然后,由于您从未将值放入 send_buf,因此从 hello 获取内存中的数据是您程序的一种可能行为。

要吸取的教训是,在各种情况下出现在数组中的“奇怪”值是它可能尚未初始化的线索,补救措施是对其进行初始化。