您的位置 首页 知识

MDK对齐方法设定

__align(4)u8mem1base[MEM1_MAX_SIZE];为何要字节对齐?从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问

__align(4) u8 mem1base[MEM1_MAX_SIZE];

为何要字节对齐?

从理论上讲如同对任何类型的变量的拜访能够从任何地址开端,但实际状况是在拜访特定类型变量的时分经常在特定的内存地址拜访,各个硬件渠道对存储空间的处理上有很大的不同。一些渠道对某些特定类型的数据只能从某些特定地址开端存取。

MDK 字节对齐关键字 __packed

typedef __packed struct abc
{
int a;
int b;
}strabc;

vxworks 字节对齐关键字 _WRS_PACK_ALIGN(1)

typedefstruct abc
{
int a;
int b;
}_WRS_PACK_ALIGN(1) strabc;

(1)什么是字节对齐
一个变量占用 n 个字节,则该变量的开端地址有必要能够被 n 整除,即: 寄存开端地址 % n = 0, 关于结构体而言,这个 n 取其成员种的数据类型占空间的值最大的那个。
(2)为什么要字节对齐
内存空间是依照字节来区分的,从理论上说对内存空间的拜访能够从任何地址开端,可是在实际上不同架构的CPU为了进步拜访内存的速度,就规矩了关于某些类 型的数据只能从特定的开端方位开端拜访。这样就决议了各种数据类型只能依照相应的规矩在内存空间中寄存,而不能一个接一个的次序排列。

举个比方,比方有些渠道拜访内存地址都从偶数地址开端,关于一个int型(假定32位体系),假如从偶数地址开端的当地寄存,这样一个读周期就能够读出这 个int数据,可是假如从奇数地址开端的地址寄存,就需求两个读周期,并对两次读出的成果的凹凸字节进行凑集才干得到这个int数据,这样显着降低了读取 的功率。
(3)怎么进行字节对齐

每个成员按其类型的对齐参数(通常是这个类型的巨细)和指定对齐参数(不指定则取默许值)中较小的一个对齐,而且结构的长度有必要为所用过的一切对齐参数的整数倍,不行就补空字节。

这个规矩有点苦涩,能够把这个规矩分化一下,前半句的意思先取得对齐值后与指定对齐值进行比较,其间对齐值取得方法如下:

1. 数据类型的本身对齐值为:关于char型数据,其本身对齐值为1,关于short型为2,关于int, long, float类型,其本身对齐值为4,关于 double 类型其本身对齐值为8,单位为字节。
2.结构体本身对齐值:其成员中本身对齐值最大的那个值。

其间指定对齐值取得方法如下:

#pragma pack (value)时的指定对齐值value。

未指定则取默许值。

后半句的意思是首要是针关于结构体的长度而言,由于针对数据类型的成员,它仅有一个对齐参数,其本身的长度、于这个对齐参数,即1倍。关于结构体而言,它 或许使用了多种数据类型,那么这句话翻译成对齐规矩: 每个成员的开端地址 % 本身对齐值 = 0,假如不等于 0 则先补空字节直至这个表达式建立。
换句话说,关于结构体而言,结构体在在内存的寄存次序用如下规矩即可映射出来:
(一)每个成员的开端地址 % 每个成员的本身对齐值 = 0,假如不等于 0 则先补空字节直至这个表达式建立;
(二)结构体的长度有必要为结构体的本身对齐值的整数倍,不行就补空字节。

举个比方:

#pragma pack(8)
struct A{
char a;
long b;
};

struct B{
char a;
struct A b;
long c;
};

struct C{
char a;
struct A b;
double c;
};

struct D{
char a;
struct A b;
double c;
int d;
};

struct E{
char a;
int b;
struct A c;
double d;
};

关于 struct A 来说,关于char型数据,其本身对齐值为1,关于long类型,其本身对齐值为4, 结构体的本身对齐值取其成员最大的对齐值,即巨细4。那么struct A 在内存中的次序过程为:
(1) char a, 地址规模为0x0000~0x0000,开端地址为0x0000,满意 0x0000 % 1 = 0,这个成员字节对齐了。
(2) long b, 地址开端方位不能从0x00001开端,由于 0x0001 % 4 != 0,所以先补空字节,直到0x00003完毕,即补3个字节的空字节,从0x00004开端寄存b,其地址规模为0x00004~0x0007.
(3)此刻成员都寄存完毕,结构体长度为8,为结构体本身对齐值的2倍,契合条件(二).
此刻满意条件(一)和条件(二),struct A 中各成员在内存中的方位为:a*** b ,sizeof(struct A) = 8。(每个星号代表一位,成员各自代表自己所占的位,比方a占一位,b占四位)

关于struct B,里边有个类型为struct A的成员b本身对齐值为4,关于long类型,其本身对齐值为4. 故struct B的本身对齐值为4。那么struct B 在内存中的次序过程为:
(1) char a, 地址规模为0x0000~0x0000,开端地址为0x0000,满意 0x0000 % 1 = 0,这个成员字节对齐了。
(2) struct A b, 地址开端方位不能从0x00001开端,由于 0x0001 % 4 != 0,所以先补空字节,直到0x00003完毕,即补3个字节的空字节,从0x00004开端寄存b,其地址规模为0x00004~0x00011.
(3) long c,地址开端方位从0x000012开端, 由于 0x0012 % 4 = 0,其地址规模为0x00012~0x0015.
(4)此刻成员都寄存完毕,结构体长度为16,为结构体本身对齐值的4倍,契合条件(二).
此刻满意条件(一)和条件(二),struct B 中各成员在内存中的方位为:a*** b c ,sizeof(struct C) = 24。(每个星号代表一位,成员各自代表自己所占的位,比方a占一位,b占八位,c占四位)
关于struct C,里边有个类型为struct A的成员b本身对齐值为4,关于double 类型,其本身对齐值为8. 故struct C的本身对齐值为8。那么struct C 在内存中的次序过程为:
(1) char a, 地址规模为0x0000~0x0000,开端地址为0x0000,满意 0x0000 % 1 = 0,这个成员字节对齐了。
(2) struct A b, 地址开端方位不能从0x00001开端,由于 0x0001 % 4 != 0,所以先补空字节,直到0x00003完毕,即补3个字节的空字节,从0x00004开端寄存b,其地址规模为0x00004~0x00011.
(3) double c,地址开端方位不能从0x000012开端, 由于 0x0012 % 8 != 0,所以先补空字节,直到0x000015完毕,即补4个字节的空字节,从0x00016开端寄存c,其地址规模为0x00016~0x0023.
(4)此刻成员都寄存完毕,结构体长度为24,为结构体本身对齐值的3倍,契合条件(二).
此刻满意条件(一)和条件(二),struct C 中各成员在内存中的方位为:a*** b **** c ,sizeof(struct C) = 24。(每个星号代表一位,成员各自代表自己所占的位,比方a占一位,b占八位,c占八位)

关于struct D,本身对齐值为8。前面三个成员与 struct C 是共同的。关于第四成员d,由于 0x0024 % 4 = 0, 所以能够从0x0024开端寄存d, 其地址规模为0x00024~0x00027.此刻成员都寄存完毕,结构体长度为28,28 不是结构体本身对齐值8的倍数,所以要在后边补四个空格,即在0x0028~0x0031上补四个空格。补完了,结构体长度为32, 为结构体自

身对齐值的4被,,契合条件(二).
此刻满意条件(一)和条件(二),struct D 中各成员在内存中的方位为:a*** b **** c d **** ,sizeof(struct D) = 32。(每个星号代表一位,成员各自代表自己所占的位,比方a占一位,b占八位,c占八位, d占四位)。

关于struct E 中各成员在内存中的方位为:a*** b c d, sizeof(struct E) = 24。(每个星号代表一位,成员各自代表自己所占的位,比方a占一位,b占四位,c占八位, d占八位)。
经过struct D 和 struct E 能够看出,在成员数量和类型共同的状况,后者的所占空间少于前者,由于后者的填充空字节要少。假如咱们在编程时考虑节省空间的话,应该遵从将变量依照类型 巨细从小到大声明的准则, 这样尽量削减添补空间。别的,能够在填充空字节的当地来刺进reserved成员, 例如
struct A
{
char a;
char reserved[3];
int b;
};
这样做的意图首要是为了对程序员起一个提示效果,假如不加则编译器会主动补齐。

习题

typedef struct

{

int a;//ARM(int=4)51(int=2)

char b;// 1

short c;// 2

}AAA;

typedef struct

{

char b;

int a;

short c;

}BBB;

i = sizeof(AAA);

j = sizeof(BBB);

//注意在51单片机,ARM,PC不同

51 (i=j=5)//如同强制单字节对齐

ARM(i=8,j=12)//按规矩默许对齐

PC(i=8,j=12)

AAA对齐方法如下(ARM)

I I I I

I0I I

BBB对齐方法如下(ARM)

I0 0 0

IIII

I I0 0

经过#pragma pack能够调整对齐字节数

#pragma pack(1) //指定Align为 1字节;

。。。。。。。。。。。。//需求对齐的结构体

#pragma pack() //康复到原先值

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/zhishi/257657.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部