【发布时间】:2021-06-03 09:01:43
【问题描述】:
#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 编译。
【问题讨论】:
-
是的,这似乎是一个明显的优化。如果数组
send_buf和hello从来没有同时使用过,那为什么不让它们共享同一个内存呢? -
这里的相关优化是live-variable analysis - 变量只需要在其实际生命周期内可用的存储空间,即在它第一次写入和最后一次读取之间。这可能是其名义生命周期的适当子集,即当它在范围内时。当然,在这种情况下,由于
send_buf未初始化,它根本就没有被写入,所以它真的没有生命周期——你已经用你的 UB 破坏了分析,任何事情都可能发生。 -
你的“已经被分配”可能是对正在发生的事情的一个好的心理构造,但是在“好像规则”下,编译器没有义务在声明发生,只要定义明确的代码无法区分。它只会影响您的代码,因为您的代码具有未定义的行为。
-
@NateEldredge:不幸的是,该标准没有努力区分不可移植的动作,这些动作在大多数实现中的行为至少在某种程度上是可预测的和错误的动作。未定义行为旨在邀请实现以怪异和古怪的方式行事,而不管通过定义超出标准要求的行为来扩展语言是否更有用,这一概念是 21 世纪的发明。
标签: arrays c gcc initialization compiler-optimization