当前位置:首页 > 芯闻号 > 充电吧
[导读]现在的一些处理器,需要你的数据的内存地址必须是对齐(align)的,即使不是必须,如果你对齐的话,运行的速度也会得到提升。虽然对齐会产生的额外内存空间,但相对于这个速度的提升来说,是值得的。 所谓对

现在的一些处理器,需要你的数据的内存地址必须是对齐(align)的,即使不是必须,如果你对齐的话,运行的速度也会得到提升。虽然对齐会产生的额外内存空间,但相对于这个速度的提升来说,是值得的。

所谓对齐,就是地址必须能整除一个整数,这个就是对齐参数(alignment value)。合法的取值范围是1、2、4、6、16、……、8192。

怎样对齐呢?编译器帮你搞定。

怎样设置编译器的对齐方式呢?用#pragma pack( n )和__declspec(align(#))。

依据它俩,编译器是咋工作的?这个就是接下来要说的了。

#include 
#pragma pack( 1 )
struct A
{             
    char a;
    short b;
    char c;
};

int main()
{
    printf("%dn",sizeof(A));
    return 0;
}
 

OK,下面对这个代码进行详细的分析。

 

用MSDN的话一言以蔽之:

“The alignment of a member (except the first one) will be on a boundary that is either a multiple of n or a multiple of the size of the member, whichever is smaller.”

翻译成中文,也就是:

“结构体中的数据成员,除了第一个是始终放在最开始的地方,其它数据成员的地址必须是它本身大小或对齐参数两者中较小的一个的倍数。”

 

P.S:注意上面所说的后面一句话,也就是说,结构体的数据成员的地址必须是本身大小和对齐参数中较小的那一个。

 

 

(1)在pack为1的时候,对齐参数是1,那么我们对这个结构体每一元素进行分析。

 

char a;        //    第一个元素在[0]位置处

 short b; //short两个字节,地址是min(1,sizeof(short))的倍数,即1的倍数[1~2]

 char c; // 地址应该是min(1,sizeof(1))的倍数,从而即为[3]

 

故在pack为1的时候,输出的结果应该是4([0~3]),其中所有的元素都填满了。

 

 

(2)在pack为2的时候,同样按照上面的方法,我们继续来分析下。

Char a; //第一个占[0]位置。

Short b; //min(2,sizeof(short)),也就是必须为2的倍数,从而[2~3]

Char c;//min(2,sizeof(char)),也就是位1,地址为[4]

因此最后占据的大小是[0],[2~3],[4],整个结构体的大小size必须是2的倍数,所以应该是6(向上对齐至2的倍数)

 

 

(3)在pack为4的时候,同上,得到的结果是

[0],[2~3],[4],因此也是6.

 

 

然后我们对上面的这个结构体变换一下顺序,可以得到。

 

struct B

{

         char a;

         char b;

         short c;

};

 

 

在#pragma pack(4)的情况下,输出却是4(注:上面的输出时6)

解释如下:

 

Char a;//占据一个字节,地址为【0】

Char b;//地址应该是min(4,sizeof(char)) = 1的倍数,也就是地址为【1】

Short c; //地址应该是min(4,sizeof(short)) = 2的倍数,也就是【2~3】

故总体占据的是【0~3】的连续单元,也就是4.

 

 

至此,我们对#prgama pack(n)的用法和对应的判定方法有了一个全新的认识。



 

特别提出:
sizeof(ao.a )还是1,sizeof(ao.b )还是2。

 如果struct B中含有A的一个对象m_a,
struct B
{
   …
   A m_a;
   …
}
则这个m_a对齐参数是A中最大的数据类型的大小(这里是short的2)和n中较小者。如果这个对齐参数是B中最大的话,最后B的大小也会与这个对齐参数有关。


m_a的对齐参数,由于是A的变量,所以采用A的对齐参数,也就是应该是A的最大元素个数和n中较小的值。而B的大小就要根据这个对齐参数来确定大小。


#include 
#include 

#define NUM 1
using namespace std;

#pragma pack ( 16 )

typedef struct {
    int a;
    char b;
    double c;
}test;

struct B
{
    int a;
    test b;
};
int main()
{
    cout << "sizeof(int) = "<     cout << "sizeof(char) = " << sizeof(char) << endl;
    cout << "sizeof(double) = " << sizeof(double) << endl;
    cout << sizeof(test)<< endl;
    cout << sizeof(B) << endl;
    system("PAUSE");
    return 0;
}

 

(1)在pack为1的时候,由于min中有一个为1,所以都是相邻存放的。

Sizeof(test)就是int+char+double的大小之和,即13.

而对应的sizeof(B)则是一个int和一个struct之和。Int占4B,而struct的对齐参数则是

Min(1,sizeof(max(A)),A中最大的元素师double类型的,也就是8,所以结果是min(1,8)=1,所以也是相邻存放的,而sizeof(A)的结果是13,所以直接是13+4 = 17.

此时,sizeof(B)的大小是17.

 

(2) 在pack为2的时候,此时min中有一个为2,对于test结构体,它的大小是4+2+8=14,因为在double的时候,min(2,8)=2,所以double类型的变量应该是2的倍数的地址,造成了char类型处空出了一个字节。总体就是14B。而对于B结构体而言,一个int占据4B,然后结构体的对齐参数采用min(2,max(A)),即min(2,8)= 2,由于是int,所以下一个地址是4,自然也是2的倍数,于是还是相邻存放。而A结构体的大小时14,于是B结构体的大小时14+4=18.

(3) 在pack为4的情况下。同样可以得到。此时对于A结构体的大小是4+4+8=16,因为double类型的必须是4的倍数,造成了char变量要占4个地方(实际只占一个,只是说这个地方空出来了3B),所以总体的大小为16.而同样对于B结构体,sizeof的结果是16+4 = 20,因为对于里面的成员要是min(4,8) = 4,而int恰好是4的倍数,所以相邻存放。于是就是16,20.

(4) 在pack为8的情况下(有所变化!!!),此时A结构体的大小是16,分析方法和上面相同,但是对于结构体B而言就有所区别,此时int还是4个字节,但是对于成员test结构体,它的对齐参数是min(8,max(A)) = min(8,sizeof(double) ) = 8也就是对齐参数是8,所以结构体变量要从地址为8开始,此时int就空出来了4B,从而最后求大小的时候应该是8+sizeof(A)= 8+16=24(最终测试结果如此)

(5)在pack为16的情况(以及以后的情况),结果是:A的大小为16B,而B的大小是24B。

 

 

总结:

(1)       对于一个由简单类型组成的结构体,它的大小是由每一个成员变量的地址决定的。我们要按照定义的顺序,分别求出来地址开始的地方。从地址为0开始,每一个变量都采取min(n,sizeof(x))//x表示该变量的类型;来确定起始地址是多少的倍数,然后开始计数,直到填满该数据。最后求出来总的大小。而且在pack>=2的时候最终的大小需要时2的倍数,有时候需要向上取大为2的倍数。而在pack为1的情况则不需要。

(2)       对于含有结构体成员的结构体,方法同上,只是在于对于结构体变量的对齐参数取法需要说明,具体就是min(n,结构体成员的最大元素的大小),就像上面的,结构体B中含有A成员,所以对齐参数就是min(n,sizeof(double))的大小,然后按照这个做法来取地址。


P.S:注意这里是pack而不是package,否则编译器会直接忽略#pragma package(),因为即使发生错误编译器也会直接忽略,而我们还是会默认认为编译器已经当做了字节按照n来处理。(某些博客上面的内容很容易让人误解或者晕倒!)

以上代码结果在Dev C++ , C-Free 5.0,VS 2010上均通过测试。



附注:在默认情况下,linux操作系统是以4字节对齐,windows操作系统则是以最大的内置类型对齐。

作用:指定结构体、联合以及类成员的packing alignment;
语法:#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。


#include


int main()
{
struct B{
char b;   //对其系数1
int a;      //对其系数4
short c;  //对其系数2
};//整体对其系数4
/*
struct A{
char b;   //对其系数1
int a;      //对其系数4
struct B f;
short c;  //对其系数2
};//整体对其系数4*/
#pragma pack(push) //保存对齐状态
#pragma pack (2)//无法识别的预处理命令


struct person{
/*char dda;
double dda1;
int type;
*/
char b;//整体对其系数1
double c; //整体对其系数8
char age;//整体对其系数1


};//整体对其系数8
#pragma pack(pop)//恢复对齐状态
struct room{
char chair[5];//整体对其系数1
int computer;//整体对其系数1
struct person children;//整体对其系数8
};
int size_r = sizeof(struct room);
int size_p = sizeof(struct person);
printf("size_r = %dnsize_p = %d", size_r,size_p);
getchar(); 
}


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭