详细说明参考博客
(1条消息) C语言结构体对齐,超详细,超易懂_haozigegie的博客-CSDN博客
(1条消息) #pragma pack详解_OuJiang2021的博客-CSDN博客_#pragma pack
以下个人理解总结
出现结构体对齐考虑的根本原因就是:【数据存取执行效率】和【存储空间】的博弈。
1、结构体对齐编译修饰
#pragma pack() 恢复默认对齐方式
#pragma pack(n ) n -1,2,4,8 对齐方式选择 ,n=1表示地址连续分配,无对齐
#pragma pack(show) 显示当前字节对齐方式的字节数,以warning显示。keil-STM32环境pack默认是8.
- n = 8 表示 1、2、4、8字节的数据都能够一次性快速读写。一般默认是8字节对齐。
- n = 4 表示 1、2、4字节数据都能一次性读写。8字节数据可能需要分成两次才能完成一次读写。
- n = 2 表示 1、2 字节的变量可以一次性读写,4字节变量可能会被分成两次才能读写。8字节可能会更多次。
- n = 1 为最紧密的存储方式。没有浪费多余的空闲地址。一般在数据打包解析数据流时用到。
#pragma pack(1)
typedef struct
{
uint8_t a;
uint16_t b;
uint32_t c;
}type1;
typedef struct
{
uint32_t c;
uint16_t b;
uint8_t a;
}type2;
type1 t1;
int test()
{
t1.a =0xFF;
t1.b = 0xFFFF;
t1.c = 0xFFFFFFFF;
type2 t2;
int size = sizeof(t1);
int size2 = sizeof(t2);
return size ;
}
此处存放未对齐32位数据用了
STR r2,[r3,#0x03]
那就是一条就赋值过去了,CotexM3有这个能力额,和开始想的两次写入有点出入。其他平台可就没这么厉害了,比如51单片机就不可以。
2、结构体大小
上文提到结构体对齐是为了快速访问存储器。
虽然在STM32上测试不对奇也有汇编指令STR快速操作存储器。这里有硬件支持不做特殊说明。但是不影响咱们去理解和接受其原理。
说明:默认状态下,pack = 8
规则1、整个结构体的大小等于其成员单个最大变量大小的整数倍数。比如结构体中变量最大2字节,那么最终结构体大小也是2的倍数。如果最大变量时4,则结构体大小就是4的倍数,以此类推。该特性用于占位结构体末尾未对齐的空间
规则2、结构体成员变量每个变量都会找到自己的位置,它自身大小时固定的,唯独它自省和前面变量空留的空间时不定的。主要满足自身大小和地址成整数倍关系就能被快速读写。uint8_类型那所有地址都是整数倍,uin16_t 那就是2的倍数地址。uint32_t 就是4的倍数地址。以此类推。
举例
typedef struct
{
uint8_t a;
uint16_t b;
uint32_t c;
}type1;
typedef struct
{
uint32_t a;
uint16_t b;
uint8_t c;
}type2;
根据规则1,type1和type2中最大的变量时4字节,所以type1,type2大小就是4的倍数,并且分配时4字节对齐。
type1.a起始地址就是4字节对齐的。 假设为type1.a地址为0x00。正常下一个地址是0x01.但是type1.b是2字节宽的数据。所以不能放在0x01地址,空一格位置。type1.b地址定位0x02.占用2字节。当前地址为0x04,刚好是4的倍数,可以做为type1.c的首地址。
type2中的a,b,c变量按照规则2都在连续的空间上,但是按照规则1,type2大小必须是4的倍数,所以type2.c之后预留了一个空的位置。