为何不同数据类型的全局符号占用相同内存长度?
这其实是**内存对齐(Memory Alignment)**在搞鬼,不是变量实际占用的大小都变成了8字节,我来给你拆解清楚:
1. x64系统下的默认内存对齐规则
在x86_64架构(也就是你说的x64机器)上,GCC默认会给全局变量设置8字节的对齐边界——这是为了让CPU能更高效地访问内存(CPU读取对齐的内存地址时,不需要拆分数据,速度更快)。
哪怕你的变量实际大小远小于8字节(比如char占1字节、int占4字节),编译器也会在变量后面自动填充空白字节(padding),让下一个变量的起始地址刚好落在8字节的倍数上。
2. nm显示的是起始地址,不是实际占用大小
你用nm看到的mango地址是0000000100402010,melon是0000000100402018,两者差8字节,这只是melon的起始地址刚好在mango的起始地址+8字节的位置,并不代表mango真的占用了8字节。
如果你想查看变量实际的大小,可以在代码里加个printf验证:
#include <stdio.h> long long mango = 13; long melon = 2001; char apple = 'a'; int orange = 100; int main() { printf("sizeof(mango): %zu\n", sizeof(mango)); // 输出8 printf("sizeof(apple): %zu\n", sizeof(apple)); // 输出1 printf("sizeof(orange): %zu\n", sizeof(orange));// 输出4 return 0; }
3. 验证对齐的影响:取消对齐试试
如果你想让变量紧密排列,去掉padding,可以用GCC的-fpack-struct编译选项,或者给变量加__attribute__((packed))属性。比如修改代码:
char apple __attribute__((packed)) = 'a'; int orange __attribute__((packed)) = 100;
再编译后用nm看地址,你会发现apple和orange的地址间隔就变成4字节(orange的实际大小),而不是8字节了。
4. Cygwin的环境因素
Cygwin是在Windows上模拟POSIX环境的工具,它的GCC行为和Linux下的x86_64 GCC基本一致,默认遵循x64的对齐规则,所以你看到的现象和Linux下编译的结果是一样的。
总结一下:你看到的地址间隔是对齐后的结果,不是变量实际占用的大小,编译器通过填充空白字节来保证内存对齐,提升CPU访问效率。
内容的提问来源于stack exchange,提问作者smwikipedia

