历史上的今天
今天是:2025年04月01日(星期二)
2019年04月01日 | STM32 字节对齐 #pragma pack
2019-04-01 来源:eefocus
1、对齐原则
min(sizeof(word ), 4) = 2,因此是 2 字节对齐,而不是我们认为的 4 字节对齐。
1)每个成员分别按自己的方式对齐,并能最小化长度;
2)复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度;
3)对齐后的结构体整体长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐。
对于数组,比如 char a[3]:
它的对齐方式和分别写 3 个 char 是一样的,也就是说它还是按 1 个字节对齐;
如果是 typedef char Array3[3]:
Array3 这种类型的对齐方式还是按 1 个字节对齐,而不是按它的长度;
不论类型是什么,对齐的边界一定是 1,2,4,8,16,32,64.... 中的一个。
2、#pragma pack 作用
指定结构体、联合以及类成员的对齐 packing alignment;
3、语法
#pragma pack ( [show] | [push | pop] [, identifier], n )
说明:
1) pack 提供数据声明级别的控制,对定义不起作用;
2) 调用 pack 时不指定参数,n 将被设成默认值;
3) 一旦改变数据类型的 alignment,直接效果就是占用 memory 的减少,但是 performance 会下降;
语法具体分析:
1) show:可选参数
显示当前packing aligment的字节数,以warning message的形式被显示;
2) push:可选参数
将当前指定的packing alignment数值进行压栈操作,这里的栈是the internal compiler stack,同时设置当前的packing alignment为n;如果n没有指定,则将当前的packing alignment数值压栈;
3) pop:可选参数
从internal compiler stack中删除最顶端的record;如果没有指定n,则当前栈顶record即为新的packing alignment数值;
如果指定了n,则n将成为新的packing aligment数值;如果指定了identifier,则internal compiler stack中的record都将被pop直到identifier被找到,然后pop出identitier,同时设置packing alignment数值为当前栈顶的record;
如果指定的identifier并不存在于internal compiler stack,则pop操作被忽略;
4) identifier:可选参数
当同push一起使用时,赋予当前被压入栈中的record一个名称;
当同pop一起使用时,从internal compiler stack中pop出所有的record直到identifier被pop出,如果identifier没有被找到,则忽略pop操作;
5) n:可选参数
指定packing的数值,以字节为单位;
缺省数值是8,合法的数值分别是1、2、4、8、16。
取消字节对齐:
#pragma pack() // 取消自定义字节对齐方式
4、重要规则
1)复杂类型中各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个类型的地址相同;
2)每个成员分别对齐,即每个成员按自己的方式对齐,并最小化长度;规则就是每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数中较小的一个对齐;
3)结构体、联合体或者类的数据成员,第一个放在偏移为0的地方;
以后每个数据成员的对齐,按照#pragma pack指定的数值和这个数据成员自身长度两个中比较小的那个进行;
也就是说,当#pragma pack指定的值等于或者超过所有数据成员长度的时候,这个指定值的大小将不产生任何效果;
4)复杂类型(如结构体)整体的对齐是按照结构体中长度最大的数据成员和#pragma pack指定值之间较小的那个值进行;
这样当数据成员为复杂类型(如结构体)时,可以最小化长度;
5)复杂类型(如结构体)整体长度的计算必须取所用过的所有对齐参数的整数倍,不够补空字节;
也就是取所用过的所有对齐参数中最大的那个值的整数倍,因为对齐参数都是2的n次方;这样在处理数组时可以保证每一项都边界对齐。
5、示例
强制对齐 #pragma pack:
#pragma pack(4) // 按 4 字节对齐,但实际上由于结构体中单个成员的最大占用字节数为 2 字节,因此实际还是按 2 字节对齐
typedef struct
{
// buf[1] 按 1 字节对齐,buf[2] 按 1 字节对齐,由于 buf[3] 的下一成员 word a 是按两字节对齐
// 因此 buf[3] 按 1 字节对齐后,后面只需补一空字节
char buf[3];
// #pragma pack(4),取小值为 2,按 2 字节对齐
word a;
} kk;
上一篇:STM32 结构体对齐规则
下一篇:STM32 启动代码分析详解
史海拾趣
|
LCD黑屏问题调试[PXA310 bootloader] 1. PXA310+DA9034+NXP5209架构的手机 2.Bug:LCD黑屏问题调试 3.任务级别:bootloader XXX:为保密公司做的项目 附件功能用不了,我用latex写的报告, 1.复制粘贴至另一个文件后,保存为一个文件,文 ...… 查看全部问答> |
|
请教一下,arm下linux正在运行,通过串口连接到电脑上,怎样把电脑上的文件传到arm里边的linux去?或者给个关键词我百度一下~… 查看全部问答> |
|
当初选择做技术,最主要的原因,是出于对科学技术的纯洁性的热爱,对人情世故的厌恶。但专于技术的工程师,要想有份有前途的工作,找到可以长久做下去的公司。“良禽择木而栖,贤臣择主而侍”,遇到下面五类性格的老板,能走多远就走多远。在此罗列 ...… 查看全部问答> |
|
想用TIM的外部时钟模式1的下做脉冲计数,可是仔细看了触发源很郁闷TS[2:0]:触发选择这3位选择用于同步计数器的触发输入。000:内部触发器0(ITR0),TIM1 001:内部触发器0(ITR1),TIM2 010:内部触发器0(ITR1),TIM3 011:内部 ...… 查看全部问答> |
|
先贴上中断部分的程序:void RTC_IRQHandler(void){ vu32 Time_temp; if (RTC_GetITStatus(RTC_IT_SEC) != RESET) { /* Clear the RTC&nbs ...… 查看全部问答> |
|
小弟用STM32做一光源控制器,其中一些相关的设置,希望能保存到Flash中,在下次开机的时候能够直接读取出来,省去重新设置的麻烦。 在保存数据的时候,我如何确定要保存到Flash的哪个地址?哪些地址是没有被代码使用到的? 代码是如何被存放 ...… 查看全部问答> |




