一、总结
1.1 先确定实际对齐单位,其由以下三个因素决定
(1) CPU周期
WIN vs qt 默认8字节对齐
Linux 32位 默认4字节对齐,64位默认8字节对齐
(2) 结构体最大成员(基本数据类型变量)
(3) 预编译指令#pragma pack(n)手动设置 n–只能填1 2 4 8 16
上面三者取最小的,就是实际对齐单位
1.2相对于结构体地址的偏移量
除结构体的第一个成员外,其他所有的成员的地址相对于结构体地址(即它首个成员的地址)的偏移量必须为实际对齐单位或自身大小的整数倍(取两者中小的那个)
大多数处理器要求对某些类型的变量进行特定的内存对齐。通常,最小对齐方式是所讨论的基本类型的大小,例如
(1) char 变量可以按字节对齐,并且可以出现在任何字节边界
(2) short(2字节)变量必须对齐2个字节,它们可以出现在任何偶数字节边界。这意味着0x10004567不是short变量的有效位置,而0x10004566是有效位置。
(3) long(4字节)变量必须对齐4字节,它们只能出现在4字节倍数的字节边界上。这意味着0x10004566不是长变量的有效位置,而0x10004568是有效位置。
之所以会出现结构成员对齐,是因为结构的成员必须出现在正确的字节边界处,为此,编译器会放入填充字节(如果使用位字段,则填充位),以便结构成员出现在正确的位置。
1.3结构体的整体大小必须为实际对齐单位的整数倍。
另外,结构的大小必须使得在结构的数组中,所有结构在内存中都正确对齐,因此结构的末尾也可能存在填充字节
二、测试验证
2.1 T1
struct test1
{ 实际地址 偏移量
uint16_t a; //0x24048864 0 地址为2的倍数
uint8_t b; //0x24048866 2 地址为1的倍数
uint32_t c; //0x24048868 4 地址为4的倍数
uint8_t d; //0x2404886C 8 地址为1的倍数
uint16_t e; //0x2404886E 10 地址为2的倍数
uint8_t f; //0x24048870 12 地址为1的倍数
uint32_t g; //0x24048874 16 地址为4的倍数
uint8_t h; //0x24048878 20 地址为1的倍数
};
struct test1 t1 = {0};
sizeof(t1) 值为24
t1.b后填充了1个字节
t1.d后填充了1个字节
t1.f后填充了3个字节
t1.h后填充了3个字节
对齐单位为 4 字节
| 0x64 | 0x66 | 0x68 | 0x6c | 0x6e | 0x70 | 0x74 | 0x78 | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| a | a | b | c | c | c | c | d | e | e | f | g | g | g | g | h |
2.2 T2
#pragma pack(4) //设置4字节对齐,但实际上由于结构体中单个成员的
//最大占用字节数为2字节,因此实际还是按2字节对齐
struct test2
{ 实际地址 偏移量
uint8_t a; //0x24048874 0 地址为1的倍数
uint8_t b; //0x24048875 1 地址为1的倍数
uint16_t c; //0x24048876 2 地址为2的倍数
uint8_t d; //0x24048878 4 地址为1的倍数
};
struct test2 t2 = {0};
sizeof(t2) 值为6
t2.d后填充了1个字节
对齐单位为 2 字节
| 0x74 | 0x75 | 0x76 | 0x78 | ||
|---|---|---|---|---|---|
| a | b | c | c | d |
————————————————
参考链接1:
https://blog.csdn.net/m0_37829435/article/details/81348532
参考链接2:
https://bytes.com/topic/c/answers/543879-what-structure-padding
497

被折叠的 条评论
为什么被折叠?



