【C】结构体的内存对齐

内存对齐的作用:

1、不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取特定类型的数据,否则抛出硬件异常(可参考【培训】考试试题1)。

2、数据结构尤其是栈,应该尽可能的在自然边界上对齐,可以让处理器尽可能的只做一次访问。

char、int、double等基础变量类型的自然对齐原则

变量地址能够被类型大小整除

数组的自然对齐原则

按数组元素的类型处理

struct自然对齐的3个原则

1、结构体变量的起始地址能够被其最宽成员类型大小整除,第一个成员地址一定等于起始地址;

2、结构体每个成员相对于起始地址的偏移能够被其自身类型大小整除,如果不能则在前一个成员后面补充字节;

3、结构体总体大小能够被最宽成员类型大小整除,如不能则在后面补充字节;

注意:如果程序中有#pragma pack(n)预编译指令,对于第1和第3原则,取n和结构体内最宽成员类型大小中的最小值作为对齐标准,用"对齐标准"替换原则中的"最宽成员类型大小"。对于第2原则,取n和每个成员自身类型大小中的最小值作为对齐标准,用"对齐标准"替换原则中的"自身类型大小"。

举例:

复制代码
struct S 
{
    char c;
    int i;
};

sizeof(struct S)为8

复制代码
struct S 
{
    double d;
    char c;
    int i;
    short s;
};        

sizeof(struct S)为24

复制代码
#pragma pack(1)
struct S 
{
    char c;
    int i;
};
#pragma pack()

sizeof(struct S)为5

复制代码
#pragma pack(4)
struct S 
{
    char c[3];
    short s;
};
#pragma pack()   

sizeof(struct S)为6,char c[3]虽然整体大小占3直接,但是每个成员还是1字节,结构体里最大成员单位是2字节,整个结构体对齐到2的整数倍。如果c是一个3字节大小结构体,结果不变,结构体大小不属于成员类型。

结构体字节对齐意义:

将一个结构体数据拷贝到一段字节缓存中,用偏移去取数据,如果结构体字节不对齐就会出问题,可以用#pragma pack(1)去修饰。在使用这种方法的时候,对于结构体里uint8_t可以直接访问,但是对于uint16_t及以上,必须用单字节拆解拼合的方式去读写,不能直接使用,寄存器地址之类的必须对齐使用。补充:如果编译优化等级不是-O0,一般的编译器会优化这种非对齐结构体,实际汇编码是单字节访问,同时对于奇地址不能强转,强转的话优化效果会消失。总结就是非对齐结构体的变量可以直接使用,但是不能把一个奇地址赋值或强转成一个偶地址指针,再使用这个指针处理变量。

union自然对齐的3个原则

1、联合体变量的起始地址能够被其最宽成员类型大小整除;

2、联合体每个成员相对于起始地址的偏移都是0;

3、联合体总体大小能够被最宽成员类型大小整除,如不能则在后面补充字节;

复制代码
union U
{
    double d;
    int i[5];
    char c;
};

sizeof(union U)为24

堆栈内存对齐( 全局或静态数据直接按自然对齐即可****)****

  1. 堆栈区的起始地址由编译器强制对齐到8字节(启动或者链接文件中配置),(UCOS上线程栈没有对齐到8字节就会出现浮点数打印异常);
  2. AAPCS(Procedure Call Standard for the Arm Architecture)规范要求栈在任何时候都保持4字节对齐,在函数调用入口点保持8字节对齐。这意味着在调用函数时,栈指针必须是8字节对齐的。但是如果某个空函数没有用栈空间,编译器会优化成4字节对齐,减少压栈(函数调用等于压栈,函数返回等于出栈,压栈==入栈,弹栈==出栈)。
  3. 中断入口函数的栈顶地址可以通过SCB(有的是NVIC)中的STKALIGN置位来对齐到8字节,如果压栈时减4字节,出栈时会自动再加4字节(栈区是由高到低,向下生长)。
  4. 局部变量的对齐原则为自然对齐,(AC5下所有局部变量地址强制对齐到4字节);
相关推荐
李松桃2 小时前
音乐爬虫 - Python
开发语言·python·python实操
Rsun045512 小时前
9、Java 外观模式从入门到实战
java·开发语言·外观模式
ICscholar2 小时前
MoE负载均衡损失 & 梯度累加除法
人工智能·学习·算法
清心歌2 小时前
TreeSet 深度解析
java·开发语言
ol木子李lo2 小时前
Qt6 替代废弃 QMediaPlaylist 的解决方案
c语言·c++·vscode·qt·个人开发·visual studio·qt6.3
Lyyaoo.2 小时前
【JAVA基础面经】juc包(java.util.concurrent)
java·开发语言
清辞8532 小时前
【Day4】C++竞赛每日练习
数据结构·c++·算法
‎ദ്ദിᵔ.˛.ᵔ₎2 小时前
C++ 继承
开发语言·c++
代码飞天2 小时前
算法与数据结构之栈、队列
数据结构·算法