结构体字节对齐
1、CPU读取内存数据
计算机的内存系统通常以块为单位进行数据传输,32位系统是4字节,64位系统是8字节。
当数据存储在对齐的地址上时,数据的起始地址正好是内存块的边界,CPU可以一次性读取完整的数据。
(1)对齐数据的访问
①如果int变量存储在地址0x1000,那么CPU可以一次读取从 0x1000~0x1003 的4字节数据
②如果double变量存储在地址0x2000,那么CPU可以一次读取从 0x2000~0x2007 的8字节数据
(2)未对齐数据的访问
① 如果int变量存储在地址0x1001,那么CPU分两次读取:0x1001~0x1003 + 0x1004
② 如果double变量存储在地址0x2002,那么CPU分两次读取:0x2002~0x2007 + 0x2008~0x2009
2、内存对齐原则
(1)第一个成员偏移0,之后每个成员的起始位置是当前成员的整数倍;
(2)如果结构体A中含有结构体B,B的起始位置是B中最大元素大小整数倍;
(3)结构体总大小是内部最大成员的整数倍。
系统默认的字节对齐值:32位系统是4字节,64位系统是8字节。
3、示例代码1
#include <stdio.h> #include <string.h> #define PRINT_SIZE(intValue) printf(#intValue" is %d\n",(intValue)); #define STRUCT_MEMBER_OFFSET(type, member) ( (char*) & ((type*)0)->member - (char*)0 ) struct employee { char *name; int num; short age; char evaluation; char *department; }; int main() { PRINT_SIZE(sizeof(struct employee)); PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, name)); PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, num)); PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, age)); PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, evaluation)); PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, department)); return 0; }
执行结果:
sizeof(struct employee) is 24 STRUCT_MEMBER_OFFSET(struct employee, name) is 0 STRUCT_MEMBER_OFFSET(struct employee, num) is 8 STRUCT_MEMBER_OFFSET(struct employee, age) is 12 STRUCT_MEMBER_OFFSET(struct employee, evaluation) is 14 STRUCT_MEMBER_OFFSET(struct employee, department) is 16
4、示例代码2
#include <stdio.h> #include <string.h> #define PRINT_SIZE(intValue) printf(#intValue" is %d\n",(intValue)); #define STRUCT_MEMBER_OFFSET(type, member) ( (char*) & ((type*)0)->member - (char*)0 ) struct student { char name[10]; int num; char sex; }; int main() { PRINT_SIZE(sizeof(struct student)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct student, name)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct student, num)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct student, sex)) return 0; }
执行结果
PS D:\Code\Data Structure> .\test.exe sizeof(struct student) is 20 STRUCT_MEMBER_OFFSET(struct student, name) is 0 STRUCT_MEMBER_OFFSET(struct student, num) is 12 STRUCT_MEMBER_OFFSET(struct student, sex) is 16
5、两种字节对齐方式
(1)#pragma pack(n)
① 指定struct
或union
成员的对齐边界为 n
字节
② n的取值为2的幂数,1, 2, 4, 8, 16
③ 如果没有指定#pragma pack,编译器会根据目标平台的默认对齐值4字节或者8字节;
④ 取n
和默认对齐值
的较小值
进行对齐
#pragma pack(1) struct Example { char a; // 1字节 int b; // 4字节 short c; // 2字节 }; #pragma pack()
n取1时,紧凑排列, Example结构体的大小=7
#pragma pack(2) struct Example { char a; // 1字节 int b; // 4字节 short c; // 2字节 }; #pragma pack()
n取2时,Example结构体的大小=8
(2)__attribute__( aligned(n) )
编译器会将让n
与默认的对齐字节数
进行比较,取较大值
为对齐字节数
(3)__attribute__( (packed) )
取消结构在编译过程中的优化对齐, 等同于#pragma pack(1)
#include <stdio.h> #include <string.h> #define PRINT_SIZE(intValue) printf(#intValue" is %ld\n",(intValue)); #define STRUCT_MEMBER_OFFSET(type, member) ( (char*) & ((type*)0)->member - (char*)0 ) typedef struct mystruct_packed { int a; double b; char c; }__attribute__((packed)) AP; typedef struct mystruct2 { int a; double b; char c; }__attribute__((aligned(2))) A2; typedef struct mystruct4 { int a; double b; char c; }__attribute__((aligned(4))) A4; typedef struct mystruct8 { int a; double b; char c; }__attribute__((aligned(8))) A8; typedef struct mystruct16 { int a; double b; char c; }__attribute__((aligned(16))) A16; typedef struct mystruct32 { int a; double b; char c; }__attribute__((aligned(32))) A32; int main() { PRINT_SIZE(sizeof(struct mystruct_packed)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct_packed, a)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct_packed, b)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct_packed, c)) printf("\n"); PRINT_SIZE(sizeof(struct mystruct2)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct2, a)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct2, b)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct2, c)) printf("\n"); PRINT_SIZE(sizeof(struct mystruct4)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct4, a)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct4, b)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct4, c)) printf("\n"); PRINT_SIZE(sizeof(struct mystruct8)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct8, a)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct8, b)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct8, c)) printf("\n"); PRINT_SIZE(sizeof(struct mystruct16)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct16, a)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct16, b)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct16, c)) printf("\n"); PRINT_SIZE(sizeof(struct mystruct32)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct32, a)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct32, b)) PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct32, c)) return 0; }
执行结果:
xuanmiao@linux:~/Test$ ./test sizeof(struct mystruct_packed) is 13 STRUCT_MEMBER_OFFSET(struct mystruct_packed, a) is 0 STRUCT_MEMBER_OFFSET(struct mystruct_packed, b) is 4 STRUCT_MEMBER_OFFSET(struct mystruct_packed, c) is 12 sizeof(struct mystruct2) is 24 STRUCT_MEMBER_OFFSET(struct mystruct2, a) is 0 STRUCT_MEMBER_OFFSET(struct mystruct2, b) is 8 STRUCT_MEMBER_OFFSET(struct mystruct2, c) is 16 sizeof(struct mystruct4) is 24 STRUCT_MEMBER_OFFSET(struct mystruct4, a) is 0 STRUCT_MEMBER_OFFSET(struct mystruct4, b) is 8 STRUCT_MEMBER_OFFSET(struct mystruct4, c) is 16 sizeof(struct mystruct8) is 24 STRUCT_MEMBER_OFFSET(struct mystruct8, a) is 0 STRUCT_MEMBER_OFFSET(struct mystruct8, b) is 8 STRUCT_MEMBER_OFFSET(struct mystruct8, c) is 16 sizeof(struct mystruct16) is 32 STRUCT_MEMBER_OFFSET(struct mystruct16, a) is 0 STRUCT_MEMBER_OFFSET(struct mystruct16, b) is 8 STRUCT_MEMBER_OFFSET(struct mystruct16, c) is 16 sizeof(struct mystruct32) is 32 STRUCT_MEMBER_OFFSET(struct mystruct32, a) is 0 STRUCT_MEMBER_OFFSET(struct mystruct32, b) is 8 STRUCT_MEMBER_OFFSET(struct mystruct32, c) is 16
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
2022-02-25 字符串函数