C语言未初始化结构体成员非随机取值现象相关疑问
现象本质说明
你观察到的所有固定表现都是特定编译环境、运行环境下的临时现象,不属于C语言标准定义的行为,绝对不能在生产代码中依赖。C标准明确规定:未显式初始化的自动存储周期(栈分配局部)对象值不确定,读取该类对象属于未定义行为。
底层原因解释
该现象和进程栈内存的初始状态、函数调用时的栈操作直接相关:
- 现代操作系统为了避免内存信息泄露,给用户进程分配的栈页初始状态都是全0清零的,程序刚启动进入
main函数时,未被使用过的栈区域值都是0。 - 对于仅包含两个
int成员的结构体:
32位环境下结构体大小为8字节,64位环境下也为8字节,你测试时main函数中调用printf前,该结构体对应的栈位置还没有被任何代码修改,所以读取到的就是初始的全0值。
对应测试代码:typedef struct st { int a; int b; } st; int main(void) { st my; printf("a: %d\n", my.a); // always 0 printf("b: %d\n", my.b); // always 0 return (0); } - 对于新增
char *成员的结构体:
64位环境下指针占8字节,整个结构体大小变为16字节,你观察到str始终为NULL、a/b为随机值的原因和printf调用的栈操作有关:printf是可变参数函数,调用时需要将参数、返回地址等数据压入栈中,这个过程刚好覆盖了结构体a、b成员对应的栈地址,把这部分内存修改为了随机值,而str成员对应的栈地址没有被覆盖,依然保留了初始的全0值(即NULL)。
对应测试代码:typedef struct st { int a; int b; char *str; } st; int main(void) { st my; printf("a: %d\n", my.a); // Random value printf("b: %d\n", my.b); // Random value printf("str: %s\n", my.str); // Always NULL return (0); } - 结构体pack不生效的原因:pack仅取消结构体内部的成员对齐填充,不会修改结构体在栈上的分配位置,也不会改变函数调用时的栈操作逻辑,因此无法改变你观察到的现象。
验证方法
你可以尝试在声明结构体后先调用一个任意空函数,再打印结构体成员值,之前表现为固定0的成员也会变为随机值,原因就是空函数的调用、返回过程修改了对应位置的栈内存。
内容的提问来源于stack exchange,提问作者ricardomart
相关产品推荐
相关产品推荐

