关于零初始化结构体未在内存中占用空间的技术咨询
关于全零初始化结构体未占用二进制文件空间的原因
这确实是个容易让人困惑的有趣细节,我来帮你拆解背后的逻辑:
核心原因:全局变量的段划分规则
在C/C++编译体系中,全局变量会根据初始化值的不同被分配到不同的段:
.data段:存储带有非零初始化值的全局/静态变量。这个段的内容会被实实在在地写入最终的二进制文件,因为需要保留初始化的非零数据。.bss段:存储全零初始化或者未初始化的全局/静态变量。这个段的特殊之处在于:它不需要在二进制文件中占用空间,只是记录需要预留的内存大小,当程序加载(或裸机环境下启动)时,由加载器/启动代码将这段内存区域统一清零。
对应到你的代码
看一下你定义的两个结构体变量:
bar1 = { "null",0 }:filename成员是字符串"null",对应的ASCII字节是0x6E, 0x75, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,并非全零,所以bar1属于非零初始化,会被编译器放到.data段,在最终的a.bin中会占用对应的12字节空间(8+4,因为__attribute__((packed))取消了对齐)。bar2 = { "",0 }:filename是空字符串,也就是8个字节全为0x00,加上filesize的0x00000000,整个结构体是全零初始化,所以被编译器分配到.bss段。
链接器的二进制输出行为
你使用的链接命令ld -melf_i386 -N --oformat binary -o a.bin a.o中,--oformat binary会让ld输出纯二进制文件。默认情况下,链接器不会把.bss段的内容写入二进制文件(因为它不需要存储数据,只需要运行时清零),所以你在a.bin中看不到bar2对应的空间,看起来就像它没占用内存——但实际上,当程序运行时,系统会为.bss段预留足够的内存并清零,bar2在运行时是有对应的内存空间的。
验证方法
你可以用以下命令查看目标文件的段信息和符号归属,确认这个结论:
- 查看目标文件的段:
你会看到readelf -S a.o.data和.bss段的定义,以及它们的大小。 - 查看符号所在的段:
输出会显示objdump -x a.o | grep -E "bar1|bar2"bar1在.data段,bar2在.bss段。
内容的提问来源于stack exchange,提问作者Bin Yan
相关产品推荐
相关产品推荐

