32位与64位编译时结构体大小差异及内存对齐填充方式疑问
32位与64位编译下GCC的结构体内存对齐差异
没错,32位和64位环境下用GCC编译时,结构体的内存对齐填充规则确实存在差异,尤其是你用的x86_64-apple-darwin17.3.0(也就是macOS High Sierra)环境里,这种差异和基础数据类型大小、平台默认对齐边界直接相关,我给你详细拆解:
1. 基础数据类型大小是差异根源
两种环境下,部分基础类型的长度不一样,这直接影响对齐逻辑:
- 32位x86环境(用
-m32编译):int、float占4字节,long占4字节,所有指针类型(void*、对象指针等)都是4字节
- 64位x86_64环境(默认编译):
int、float还是4字节,但long变成8字节,所有指针类型统一为8字节
2. 默认对齐边界的不同
GCC的默认对齐逻辑是:结构体的对齐边界等于其内部最大基础成员的大小,同时还要遵循平台的默认对齐限制:
- 32位环境下,默认最大对齐边界是4字节(因为最大基础类型是4字节)
- 64位环境下,默认最大对齐边界是8字节(因为指针和
long都是8字节)
举个直观的例子,比如下面这个结构体:
struct Test { char c; void* ptr; };
- 32位编译时:
char占1字节,会填充3字节凑到4字节对齐,接着ptr占4字节,总大小为8字节 - 64位编译时:
char占1字节,需要填充7字节凑到8字节对齐,再加上ptr的8字节,总大小为16字节
3. macOS环境的特殊注意点
你用的x86_64-apple-darwin环境中,GCC的对齐行为和Linux x86_64基本一致,但要注意:在32位模式下,long long虽然是8字节,但平台默认对齐边界还是4字节,所以包含long long的结构体,32位下会按4字节对齐来填充。比如:
struct TestLL { char c; long long ll; };
- 32位编译总大小是12字节:
char占1字节,填充3字节到4字节,long long占8字节,总和12 - 64位编译总大小是16字节:
char占1字节,填充7字节到8字节,long long占8字节,总和16
如果想要强制取消对齐填充,可以给结构体加上__attribute__((packed))属性,这样32位和64位下结构体大小就等于所有成员的总字节数,但这种做法可能会导致性能下降,甚至在某些平台触发未对齐访问的硬件错误,需要谨慎使用。
内容的提问来源于stack exchange,提问作者Iliketoproveit
相关产品推荐
相关产品推荐

