关于pragma pack的用法--------------C 中的内存对齐问题(转载)

news/2024/6/29 12:01:08 标签: struct, 编译器, c, alignment, class, 存储
class="tags" href="/tags/C.html" title=c>cle class="tags" href="/tags/C.html" title=c>class="baidu_pl">
class="tags" href="/tags/C.html" title=c>cle_class="tags" href="/tags/C.html" title=c>content" class="tags" href="/tags/C.html" title=c>class="articlass="tags" href="/tags/C.html" title=c>cle_class="tags" href="/tags/C.html" title=c>content class="tags" href="/tags/C.html" title=c>clearfix">
class="tags" href="/tags/C.html" title=c>content_views" class="tags" href="/tags/C.html" title=c>class="htmledit_views">

http://www.360doclass="tags" href="/tags/C.html" title=c>c.class="tags" href="/tags/C.html" title=c>com/class="tags" href="/tags/C.html" title=c>content/10/0124/00/722458_14261259.shtml

为了能使CPU对变量进行高效快速的访问࿰class="tags" href="/tags/C.html" title=c>c;变量的起始地址应该具有某些特性࿰class="tags" href="/tags/C.html" title=c>c;即所谓的“对齐”。例如对于4字节的int类型变量࿰class="tags" href="/tags/C.html" title=c>c;其起始地址应位于4字节边界上࿰class="tags" href="/tags/C.html" title=c>c;即起始地址能够被4整除。变量的对齐规则如下(32位系统):
Type
Alignment
class="tags" href="/tags/C.html" title=c>char
在字节边界上对齐
short (16-bit)
在双字节边界上对齐
int and long (32-bit)
在4字节边界上对齐
float
在4字节边界上对齐
double
在8字节边界上对齐
class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ctures
单独考虑结构体的个成员࿰class="tags" href="/tags/C.html" title=c>c;它们在不同的字节边界上对齐。
其中最大的字节边界数就是该结构的字节边界数。

如果结构体中有结构体成员࿰class="tags" href="/tags/C.html" title=c>c;那么这是一个递归的过程。
class="tags" href="/tags/C.html" title=c>color: #0000ff;">设class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/BianYiQi.html" title=编译器>编译器设定的最大对齐字节边界数为n࿰class="tags" href="/tags/C.html" title=c>c;对于结构体中的某一成员item࿰class="tags" href="/tags/C.html" title=c>c;它相对于结构首地址的实际字节对齐数

class="tags" href="/tags/C.html" title=c>color: #0000ff;">目X应该满足以下规则:
X = min(n, sizeof(item))
例如࿰class="tags" href="/tags/C.html" title=c>c;对于结构体
class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct {
class="tags" href="/tags/C.html" title=c>char a;
long b;
} T;
当位于32位系统࿰class="tags" href="/tags/C.html" title=c>c;n=8时:
a的偏移为0࿰class="tags" href="/tags/C.html" title=c>c;
b的偏移为4࿰class="tags" href="/tags/C.html" title=c>c;中间填充了3个字节, b的X为4;

当位于32位系统࿰class="tags" href="/tags/C.html" title=c>c;n=2时:
a的偏移为0࿰class="tags" href="/tags/C.html" title=c>c;
b的偏移为2࿰class="tags" href="/tags/C.html" title=c>c;中间填充了1个字节࿰class="tags" href="/tags/C.html" title=c>c;b的X为2;
结构体的sizeof:
设结构体的最后一个成员为LastItem࿰class="tags" href="/tags/C.html" title=c>c;其相对于结构体首地址的偏移为offset(LastItem)࿰class="tags" href="/tags/C.html" title=c>c;其大小为 sizeof(LastItem)࿰class="tags" href="/tags/C.html" title=c>c;结构体的字节对齐数为N࿰class="tags" href="/tags/C.html" title=c>c;则:结构体的sizeof 为: 若offset(LastItem)+ sizeof(LastItem)能够被N整除࿰class="tags" href="/tags/C.html" title=c>c;那么就是offset(LastItem)+ sizeof(LastItem)࿰class="tags" href="/tags/C.html" title=c>c;否则࿰class="tags" href="/tags/C.html" title=c>c;在后面填充࿰class="tags" href="/tags/C.html" title=c>c;直到能够被N整除。
另外:
1) class="tags" href="/tags/C.html" title=c>color: #0000ff;">对于空结构体࿰class="tags" href="/tags/C.html" title=c>c;sizeof == 1;因为必须保证结构体的每一个实例在内存中都有独一无二的地址.
2)class="tags" href="/tags/C.html" title=c>color: #0000ff;">结构体的静态成员不对结构体的大小产生影响࿰class="tags" href="/tags/C.html" title=c>c;因为静态变量的存储位置与结构体的实例地址无关。例如:
class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct {staticlass="tags" href="/tags/C.html" title=c>c int I;} T; class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct {class="tags" href="/tags/C.html" title=c>char a; staticlass="tags" href="/tags/C.html" title=c>c int I;} T1;
sizeof(T) == 1; sizeof(T1) == 1;

下面是CSDN上提出的问题(原文<>:http://class="tags" href="/tags/C.html" title=c>community.class="tags" href="/tags/C.html" title=c>csdn.net/Expert/Topiclass="tags" href="/tags/C.html" title=c>cView3.asp?id=3804035)
---------------------------------------
#pragma paclass="tags" href="/tags/C.html" title=c>ck(8)

class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct s1{
short a;
long b;
};

class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct s2{
class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c;
s1 d;
long long e;
};

#pragma paclass="tags" href="/tags/C.html" title=c>ck()


1.sizeof(s2) = ?
2.s2的class="tags" href="/tags/C.html" title=c>c后面空了几个字节接着是d?
---------------------------------------

下面是redleaves(ID最吊的网友)给出的解释:
很详尽,很透彻,从论坛原文后头的对话可以看出redleaves对C/C++的标准理解很深刻,值得偶学习:)
#pragma paclass="tags" href="/tags/C.html" title=c>ck(8)
class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct S1{
class="tags" href="/tags/C.html" title=c>char a;
long b;
};
class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct S2 {
class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c;
class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct S1 d;
long long e;
};
#pragma paclass="tags" href="/tags/C.html" title=c>ck()
sizeof(S2)结果为24.
成员对齐有一个重要的条件,即每个成员分别对齐.即每个成员按自己的方式对齐.
也就是说上面虽然指定了按8字节对齐,但并不是所有的成员都是以8字节对齐.其对齐的规则是,每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里是8字节)中较小的一个对齐.并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节.
S1中,成员a是1字节默认按1字节对齐,指定对齐参数为8,这两个值中取1,a按1字节对齐;成员b是4个字节,默认是按4字节对齐,这时就按4字节对齐,所以sizeof(S1)应该为8;
S2 中,class="tags" href="/tags/C.html" title=c>c和S1中的a一样,按1字节对齐,而d 是个结构,它是8个字节,它按什么对齐呢?对于结构来说,它的默认对齐方式就是它的所有成员使用的对齐参数中最大的一个,S1的就是4.所以,成员d就是按4字节对齐.成员e是8个字节,它是默认按8字节对齐,和指定的一样,所以它对到8字节的边界上,这时,已经使用了12个字节了,所以又添加了4个字节的空,从第16个字节开始放置成员e.这时,长度为24,已经可以被8(成员e按8字节对齐)整除.这样,一共使用了24个字节.
a b
S1的内存布局:11**,1111,
class="tags" href="/tags/C.html" title=c>c S1.a S1.b d
S2的内存布局:1***,11**,1111,****11111111

这里有三点很重要:
1.每个成员分别按自己的方式对齐,并能最小化长度
2.复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度
3.对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐

对于数组,比如:
class="tags" href="/tags/C.html" title=c>char a[3];这种,它的对齐方式和分别写3个class="tags" href="/tags/C.html" title=c>char是一样的.也就是说它还是按1个字节对齐.
如果写: typedef class="tags" href="/tags/C.html" title=c>char Array3[3];
Array3这种类型的对齐方式还是按1个字节对齐,而不是按它的长度.
不论类型是什么,对齐的边界一定是1,2,4,8,16,32,64....中的一个.

如下一段代码:
#pragma paclass="tags" href="/tags/C.html" title=c>ck(4)
class="tags" href="/tags/C.html" title=c>class TestB
{
publiclass="tags" href="/tags/C.html" title=c>c:
int aa;
class="tags" href="/tags/C.html" title=c>char a;
short b;
class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c;
};
int nSize = sizeof(TestB);
这里nSize结果为12࿰class="tags" href="/tags/C.html" title=c>c;在预料之中。

  现在去掉第一个成员变量为如下代码:
#pragma paclass="tags" href="/tags/C.html" title=c>ck(4)
class="tags" href="/tags/C.html" title=c>class TestC
{
publiclass="tags" href="/tags/C.html" title=c>c:
class="tags" href="/tags/C.html" title=c>char a;
short b;
class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c;
};
int nSize = sizeof(TestC);
按照正常的填充方式nSize的结果应该是8࿰class="tags" href="/tags/C.html" title=c>c;为什么结果显示nSize为6呢?

事实上࿰class="tags" href="/tags/C.html" title=c>c;很多人对#pragma paclass="tags" href="/tags/C.html" title=c>ck的理解是错误的。
#pragma paclass="tags" href="/tags/C.html" title=c>ck规定的对齐长度࿰class="tags" href="/tags/C.html" title=c>c;实际使用的规则是:
结构࿰class="tags" href="/tags/C.html" title=c>c;联合࿰class="tags" href="/tags/C.html" title=c>c;或者类的数据成员࿰class="tags" href="/tags/C.html" title=c>c;第一个放在偏移为0的地方࿰class="tags" href="/tags/C.html" title=c>c;以后每个数据成员的对齐࿰class="tags" href="/tags/C.html" title=c>c;按照#pragma paclass="tags" href="/tags/C.html" title=c>ck指定的数值和这个数据成员自身长度中࿰class="tags" href="/tags/C.html" title=c>c;比较小的那个进行。
也就是说࿰class="tags" href="/tags/C.html" title=c>c;当#pragma paclass="tags" href="/tags/C.html" title=c>ck的值等于或超过所有数据成员长度的时候࿰class="tags" href="/tags/C.html" title=c>c;这个值的大小将不产生任何效果。
而结构整体的对齐࿰class="tags" href="/tags/C.html" title=c>c;则按照结构体中最大的数据成员和 #pragma paclass="tags" href="/tags/C.html" title=c>ck指定值 之间࿰class="tags" href="/tags/C.html" title=c>c;较小的那个进行。

具体解释
#pragma paclass="tags" href="/tags/C.html" title=c>ck(4)
class="tags" href="/tags/C.html" title=c>class TestB
{
publiclass="tags" href="/tags/C.html" title=c>c:
int aa; //第一个成员࿰class="tags" href="/tags/C.html" title=c>c;放在[0,3]偏移的位置࿰class="tags" href="/tags/C.html" title=c>c;
class="tags" href="/tags/C.html" title=c>char a; //第二个成员࿰class="tags" href="/tags/C.html" title=c>c;自身长为1࿰class="tags" href="/tags/C.html" title=c>c;#pragma paclass="tags" href="/tags/C.html" title=c>ck(4),取小值࿰class="tags" href="/tags/C.html" title=c>c;也就是1࿰class="tags" href="/tags/C.html" title=c>c;所以这个成员按一字节对齐࿰class="tags" href="/tags/C.html" title=c>c;放在偏移[4]的位置。
short b; //第三个成员࿰class="tags" href="/tags/C.html" title=c>c;自身长2࿰class="tags" href="/tags/C.html" title=c>c;#pragma paclass="tags" href="/tags/C.html" title=c>ck(4)࿰class="tags" href="/tags/C.html" title=c>c;取2࿰class="tags" href="/tags/C.html" title=c>c;按2字节对齐࿰class="tags" href="/tags/C.html" title=c>c;所以放在偏移[6,7]的位置。
class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c; //第四个࿰class="tags" href="/tags/C.html" title=c>c;自身长为1࿰class="tags" href="/tags/C.html" title=c>c;放在[8]的位置。
};
这个类实际占据的内存空间是9字节
class="tags" href="/tags/C.html" title=c>color: #0000ff;">类之间的对齐࿰class="tags" href="/tags/C.html" title=c>c;是按照类内部最大的成员的长度࿰class="tags" href="/tags/C.html" title=c>c;和#pragma paclass="tags" href="/tags/C.html" title=c>ck规定的值之中较小的一个对齐的
所以这个例子中࿰class="tags" href="/tags/C.html" title=c>c;类之间对齐的长度是min(sizeof(int),4)࿰class="tags" href="/tags/C.html" title=c>c;也就是4。
9按照4字节圆整的结果是12࿰class="tags" href="/tags/C.html" title=c>c;所以sizeof(TestB)是12。


如果
#pragma paclass="tags" href="/tags/C.html" title=c>ck(2)
class="tags" href="/tags/C.html" title=c>class TestB
{
publiclass="tags" href="/tags/C.html" title=c>c:
int aa; //第一个成员࿰class="tags" href="/tags/C.html" title=c>c;放在[0,3]偏移的位置࿰class="tags" href="/tags/C.html" title=c>c;
class="tags" href="/tags/C.html" title=c>char a; //第二个成员࿰class="tags" href="/tags/C.html" title=c>c;自身长为1࿰class="tags" href="/tags/C.html" title=c>c;#pragma paclass="tags" href="/tags/C.html" title=c>ck(4),取小值࿰class="tags" href="/tags/C.html" title=c>c;也就是1࿰class="tags" href="/tags/C.html" title=c>c;所以这个成员按一字节对齐࿰class="tags" href="/tags/C.html" title=c>c;放在偏移[4]的位置。
short b; //第三个成员࿰class="tags" href="/tags/C.html" title=c>c;自身长2࿰class="tags" href="/tags/C.html" title=c>c;#pragma paclass="tags" href="/tags/C.html" title=c>ck(4)࿰class="tags" href="/tags/C.html" title=c>c;取2࿰class="tags" href="/tags/C.html" title=c>c;按2字节对齐࿰class="tags" href="/tags/C.html" title=c>c;所以放在偏移[6,7]的位置。
class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c; //第四个࿰class="tags" href="/tags/C.html" title=c>c;自身长为1࿰class="tags" href="/tags/C.html" title=c>c;放在[8]的位置。
};
//可以看出࿰class="tags" href="/tags/C.html" title=c>c;上面的位置完全没有变化࿰class="tags" href="/tags/C.html" title=c>c;只是类之间改为按2字节对齐࿰class="tags" href="/tags/C.html" title=c>c;9按2圆整的结果是10。
//所以 sizeof(TestB)是10。

最后看原贴:
现在去掉第一个成员变量为如下代码:
#pragma paclass="tags" href="/tags/C.html" title=c>ck(4)
class="tags" href="/tags/C.html" title=c>class TestC
{
publiclass="tags" href="/tags/C.html" title=c>c:
class="tags" href="/tags/C.html" title=c>char a;//第一个成员࿰class="tags" href="/tags/C.html" title=c>c;放在[0]偏移的位置࿰class="tags" href="/tags/C.html" title=c>c;
short b;//第二个成员࿰class="tags" href="/tags/C.html" title=c>c;自身长2࿰class="tags" href="/tags/C.html" title=c>c;#pragma paclass="tags" href="/tags/C.html" title=c>ck(4)࿰class="tags" href="/tags/C.html" title=c>c;取2࿰class="tags" href="/tags/C.html" title=c>c;按2字节对齐࿰class="tags" href="/tags/C.html" title=c>c;所以放在偏移[2,3]的位置。
class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c;//第三个࿰class="tags" href="/tags/C.html" title=c>c;自身长为1࿰class="tags" href="/tags/C.html" title=c>c;放在[4]的位置。
};
//整个类的大小是5字节࿰class="tags" href="/tags/C.html" title=c>c;按照min(sizeof(short),4)字节对齐࿰class="tags" href="/tags/C.html" title=c>c;也就是2字节对齐࿰class="tags" href="/tags/C.html" title=c>c;结果是6
//所以sizeof(TestC)是6。

感谢 class="tags" href="/tags/C.html" title=c>color: #1848b5;">Miclass="tags" href="/tags/C.html" title=c>chael 提出疑问࿰class="tags" href="/tags/C.html" title=c>c;在此补充:

#pragma paclass="tags" href="/tags/C.html" title=c>ck



当数据定义中出现__declass="tags" href="/tags/C.html" title=c>clspeclass="tags" href="/tags/C.html" title=c>c( align() )时࿰class="tags" href="/tags/C.html" title=c>c;指定类型的对齐长度还要用自身长度和这里指定的数值比较࿰class="tags" href="/tags/C.html" title=c>c;然后取其中较大的。最终类/结构的对齐长度也需要和这个数值比较࿰class="tags" href="/tags/C.html" title=c>c;然后取其中较大的。

可以这样理解࿰class="tags" href="/tags/C.html" title=c>c; __declass="tags" href="/tags/C.html" title=c>clspeclass="tags" href="/tags/C.html" title=c>c( align() ) 和 #pragma paclass="tags" href="/tags/C.html" title=c>ck是一对兄弟࿰class="tags" href="/tags/C.html" title=c>c;前者规定了对齐的最小值࿰class="tags" href="/tags/C.html" title=c>c;后者规定了对齐的最大值࿰class="tags" href="/tags/C.html" title=c>c;两者同时出现时࿰class="tags" href="/tags/C.html" title=c>c;前者拥有更高的优先级。
__declass="tags" href="/tags/C.html" title=c>clspeclass="tags" href="/tags/C.html" title=c>c ( align() )的一个特点是࿰class="tags" href="/tags/C.html" title=c>c;它仅仅规定了数据对齐的位置࿰class="tags" href="/tags/C.html" title=c>c;而没有规定数据实际占用的内存长度࿰class="tags" href="/tags/C.html" title=c>c;当指定的数据被放置在确定的位置之后࿰class="tags" href="/tags/C.html" title=c>c;其后的数据填充仍然是按照#pragma paclass="tags" href="/tags/C.html" title=c>ck规定的方式填充的࿰class="tags" href="/tags/C.html" title=c>c;这时候类/结构的实际大小和内存格局的规则是这样的:
在__declass="tags" href="/tags/C.html" title=c>clspeclass="tags" href="/tags/C.html" title=c>c( align () )之前࿰class="tags" href="/tags/C.html" title=c>c;数据按照#pragma paclass="tags" href="/tags/C.html" title=c>ck规定的方式填充࿰class="tags" href="/tags/C.html" title=c>c;如前所述。当遇到__declass="tags" href="/tags/C.html" title=c>clspeclass="tags" href="/tags/C.html" title=c>c( align() )的时候࿰class="tags" href="/tags/C.html" title=c>c;首先寻找距离当前偏移向后最近的对齐点(满足对齐长度为 max(数据自身长度,指定值) )࿰class="tags" href="/tags/C.html" title=c>c;然后把被指定的数据类型从这个点开始填充࿰class="tags" href="/tags/C.html" title=c>c;其后的数据类型从它的后面开始࿰class="tags" href="/tags/C.html" title=c>c;仍然按照#pragma paclass="tags" href="/tags/C.html" title=c>ck填充࿰class="tags" href="/tags/C.html" title=c>c;直到遇到下一个__declass="tags" href="/tags/C.html" title=c>clspeclass="tags" href="/tags/C.html" title=c>c( align() )。
当所有数据填充完毕࿰class="tags" href="/tags/C.html" title=c>c;把结构的整体对齐数值和__declass="tags" href="/tags/C.html" title=c>clspeclass="tags" href="/tags/C.html" title=c>c( align() )规定的值做比较࿰class="tags" href="/tags/C.html" title=c>c;取其中较大的作为整个结构的对齐长度。
特别的࿰class="tags" href="/tags/C.html" title=c>c;当__declass="tags" href="/tags/C.html" title=c>clspeclass="tags" href="/tags/C.html" title=c>c( align() )指定的数值比对应类型长度小的时候࿰class="tags" href="/tags/C.html" title=c>c;这个指定不起作用。




class="tags" href="/tags/C.html" title=c>class="blogstory">

 首先请大家先看下面代码:
    typedef class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct
    {
      UINT32  NumElements;
      union
      {
         UINT32  Objeclass="tags" href="/tags/C.html" title=c>ctHandle;
       }Entry;
     }STR_ARRAY, *PSTR_ARRAY;

    还有这两句#pragma paclass="tags" href="/tags/C.html" title=c>ck(push, 1)
    #pragma paclass="tags" href="/tags/C.html" title=c>ck(pop)
    #pragma  paclass="tags" href="/tags/C.html" title=c>ck( [ n ] )

    该指令指定结构和联合成员的紧凑对齐。而一个完整的转换单元的结构和联合的紧凑对齐由/ Z p 选项设置。紧凑对齐用p a class="tags" href="/tags/C.html" title=c>c e 编译指示在数据说明层设置。该编译指示在其出现后的第一个结构或联合说明处生效。该编译指示对定义无效。当你使用#pragma  paclass="tags" href="/tags/C.html" title=c>ck ( n ) 时, 这里n 为1 、2 、4 、8 或1 6 。第一个结构成员之后的每个结构成员都被存储在更小的成员类型或n 字节界限内。如果你使用无参量的#pragma  paclass="tags" href="/tags/C.html" title=c>ck , 结构成员被紧凑为以/ Z p 指定的值。该缺省/ Z p 紧凑值为/ Z p 8 。

    class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/BianYiQi.html" title=编译器>编译器也支持以下增强型语法:
    #pragma  paclass="tags" href="/tags/C.html" title=c>ck( [ [ { p u s h | p o p } , ] [ 标识符, ] ] [ n] )若不同的组件使用p a class="tags" href="/tags/C.html" title=c>c k 编译指示指定不同的紧凑对齐, 这个语法允许你把程序组件组合为一个单独的转换单元。带p u s h 参量的p a class="tags" href="/tags/C.html" title=c>c k 编译指示的每次出现将当前的紧凑对齐存储到一个内部class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/BianYiQi.html" title=编译器>编译器堆栈中。编译指示的参量表从左到右读取。如果你使用p u s h , 则当前紧凑值被存储起来; 如果你给出一个n 的值, 该值将成为新的紧凑值。若你指定一个
标识符, 即你选定一个名称, 则该标识符将和这个新的的紧凑值联系起来。带一个p o p 参量的p a class="tags" href="/tags/C.html" title=c>c k 编译指示的每次出现都会检索内部class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/BianYiQi.html" title=编译器>编译器堆栈顶的值,并且使该值为新的紧凑对齐值。如果你使用p o p 参量且内部class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/BianYiQi.html" title=编译器>编译器堆栈是空的,则紧凑值为命令行给定的值, 并且将产生一个警告信息。若你使用p o p 且指定一
个n 的值, 该值将成为新的紧凑值。若你使用p o p 且指定一个标识符,  所有存储在堆栈中的值将从栈中删除, 直到找到一个匹配的标识符, 这个与标识符相关的紧凑值也从栈中移出, 并且这个仅在标识符入栈之前存在的紧凑值成为新的紧凑值。如果未找到匹配的标识符, 将使用命令行设置的紧凑值, 并且将产生一个一级警告。缺省紧凑对齐为8 。p a class="tags" href="/tags/C.html" title=c>c k 编译指示的新的增强功能让你编写头文件, 确保在遇到该头文件的前后的紧凑值是一样的。

    什么是内存对齐

    考虑下面的结构:

         class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct foo
         {
           class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c1;
           short s;
           class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c2;
           int i;
          };
   
    假设这个结构的成员在内存中是紧凑排列的࿰class="tags" href="/tags/C.html" title=c>c;假设class="tags" href="/tags/C.html" title=c>c1的地址是0࿰class="tags" href="/tags/C.html" title=c>c;那么s的地址就应该是1࿰class="tags" href="/tags/C.html" title=c>c;class="tags" href="/tags/C.html" title=c>c2的地址就是3࿰class="tags" href="/tags/C.html" title=c>c;i的地址就是4。也就是
    class="tags" href="/tags/C.html" title=c>c1 00000000, s 00000001, class="tags" href="/tags/C.html" title=c>c2 00000003, i 00000004。

    可是࿰class="tags" href="/tags/C.html" title=c>c;我们在Visual class="tags" href="/tags/C.html" title=c>c/class="tags" href="/tags/C.html" title=c>c++ 6中写一个简单的程序:

         class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct foo a;
    printf("class="tags" href="/tags/C.html" title=c>c1 %p, s %p, class="tags" href="/tags/C.html" title=c>c2 %p, i %p/n",
        (unsigned int)(void*)&a.class="tags" href="/tags/C.html" title=c>c1 - (unsigned int)(void*)&a,
        (unsigned int)(void*)&a.s - (unsigned int)(void*)&a,
        (unsigned int)(void*)&a.class="tags" href="/tags/C.html" title=c>c2 - (unsigned int)(void*)&a,
        (unsigned int)(void*)&a.i - (unsigned int)(void*)&a);
    运行࿰class="tags" href="/tags/C.html" title=c>c;输出:
         class="tags" href="/tags/C.html" title=c>c1 00000000, s 00000002, class="tags" href="/tags/C.html" title=c>c2 00000004, i 00000008。

    为什么会这样?这就是内存对齐而导致的问题。

为什么会有内存对齐

    以下内容节选自《Intel Arclass="tags" href="/tags/C.html" title=c>chiteclass="tags" href="/tags/C.html" title=c>cture 32 Manual》。
    字࿰class="tags" href="/tags/C.html" title=c>c;双字࿰class="tags" href="/tags/C.html" title=c>c;和四字在自然边界上不需要在内存中对齐。(对字࿰class="tags" href="/tags/C.html" title=c>c;双字࿰class="tags" href="/tags/C.html" title=c>c;和四字来说࿰class="tags" href="/tags/C.html" title=c>c;自然边界分别是偶数地址࿰class="tags" href="/tags/C.html" title=c>c;可以被4整除的地址࿰class="tags" href="/tags/C.html" title=c>c;和可以被8整除的地址。)
    无论如何࿰class="tags" href="/tags/C.html" title=c>c;为了提高程序的性能࿰class="tags" href="/tags/C.html" title=c>c;数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于࿰class="tags" href="/tags/C.html" title=c>c;为了访问未对齐的内存࿰class="tags" href="/tags/C.html" title=c>c;处理器需要作两次内存访问;然而࿰class="tags" href="/tags/C.html" title=c>c;对齐的内存访问仅需要一次访问。
    一个字或双字操作数跨越了4字节边界࿰class="tags" href="/tags/C.html" title=c>c;或者一个四字操作数跨越了8字节边界࿰class="tags" href="/tags/C.html" title=c>c;被认为是未对齐的࿰class="tags" href="/tags/C.html" title=c>c;从而需要两次总线周期来访问内存。一个字起始地址是奇数但却没有跨越字边界被认为是对齐的࿰class="tags" href="/tags/C.html" title=c>c;能够在一个总线周期中被访问。
    某些操作双四字的指令需要内存操作数在自然边界上对齐。如果操作数没有对齐࿰class="tags" href="/tags/C.html" title=c>c;这些指令将会产生一个通用保护异常(#GP)。双四字的自然边界是能够被16 整除的地址。其他的操作双四字的指令允许未对齐的访问(不会产生通用保护异常)࿰class="tags" href="/tags/C.html" title=c>c;然而࿰class="tags" href="/tags/C.html" title=c>c;需要额外的内存总线周期来访问内存中未对齐的数据。

class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/BianYiQi.html" title=编译器>编译器对内存对齐的处理

    缺省情况下࿰class="tags" href="/tags/C.html" title=c>c;class="tags" href="/tags/C.html" title=c>c/class="tags" href="/tags/C.html" title=c>c++class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/BianYiQi.html" title=编译器>编译器默认将结构、栈中的成员数据进行内存对齐。因此࿰class="tags" href="/tags/C.html" title=c>c;上面的程序输出就变成了:
class="tags" href="/tags/C.html" title=c>c1 00000000, s 00000002, class="tags" href="/tags/C.html" title=c>c2 00000004, i 00000008。
class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/BianYiQi.html" title=编译器>编译器将未对齐的成员向后移࿰class="tags" href="/tags/C.html" title=c>c;将每一个都成员对齐到自然边界上࿰class="tags" href="/tags/C.html" title=c>c;从而也导致了整个结构的尺寸变大。尽管会牺牲一点空间(成员之间有空洞)࿰class="tags" href="/tags/C.html" title=c>c;但提高了性能。
也正是这个原因࿰class="tags" href="/tags/C.html" title=c>c;我们不可以断言sizeof(foo) == 8。在这个例子中࿰class="tags" href="/tags/C.html" title=c>c;sizeof(foo) == 12。

如何避免内存对齐的影响

    那么࿰class="tags" href="/tags/C.html" title=c>c;能不能既达到提高性能的目的࿰class="tags" href="/tags/C.html" title=c>c;又能节约一点空间呢?有一点小技巧可以使用。比如我们可以将上面的结构改成:

    class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct bar
    {
        class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c1;
        class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c2;
        short s;
        int i;
    };
    这样一来࿰class="tags" href="/tags/C.html" title=c>c;每个成员都对齐在其自然边界上࿰class="tags" href="/tags/C.html" title=c>c;从而避免了class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/BianYiQi.html" title=编译器>编译器自动对齐。在这个例子中࿰class="tags" href="/tags/C.html" title=c>c;sizeof(bar) == 8。

    这个技巧有一个重要的作用࿰class="tags" href="/tags/C.html" title=c>c;尤其是这个结构作为API的一部分提供给第三方开发使用的时候。第三方开发者可能将class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/BianYiQi.html" title=编译器>编译器的默认对齐选项改变࿰class="tags" href="/tags/C.html" title=c>c;从而造成这个结构在你的发行的DLL中使用某种对齐方式࿰class="tags" href="/tags/C.html" title=c>c;而在第三方开发者哪里却使用另外一种对齐方式。这将会导致重大问题。
    比如࿰class="tags" href="/tags/C.html" title=c>c;foo结构࿰class="tags" href="/tags/C.html" title=c>c;我们的DLL使用默认对齐选项࿰class="tags" href="/tags/C.html" title=c>c;对齐为
class="tags" href="/tags/C.html" title=c>c1 00000000, s 00000002, class="tags" href="/tags/C.html" title=c>c2 00000004, i 00000008࿰class="tags" href="/tags/C.html" title=c>c;同时sizeof(foo) == 12。
而第三方将对齐选项关闭࿰class="tags" href="/tags/C.html" title=c>c;导致
    class="tags" href="/tags/C.html" title=c>c1 00000000, s 00000001, class="tags" href="/tags/C.html" title=c>c2 00000003, i 00000004࿰class="tags" href="/tags/C.html" title=c>c;同时sizeof(foo) == 8。

如何使用class="tags" href="/tags/C.html" title=c>c/class="tags" href="/tags/C.html" title=c>c++中的对齐选项

    vclass="tags" href="/tags/C.html" title=c>c6中的编译选项有 /Zp[1|2|4|8|16] ࿰class="tags" href="/tags/C.html" title=c>c;/Zp1表示以1字节边界对齐࿰class="tags" href="/tags/C.html" title=c>c;相应的࿰class="tags" href="/tags/C.html" title=c>c;/Zpn表示以n字节边界对齐。n字节边界对齐的意思是说࿰class="tags" href="/tags/C.html" title=c>c;一个成员的地址必须安排在成员的尺寸的整数倍地址上或者是n的整数倍地址上࿰class="tags" href="/tags/C.html" title=c>c;取它们中的最小值。也就是:
    min ( sizeof ( member ),  n)
    实际上࿰class="tags" href="/tags/C.html" title=c>c;1字节边界对齐也就表示了结构成员之间没有空洞。
    /Zpn选项是应用于整个工程的࿰class="tags" href="/tags/C.html" title=c>c;影响所有的参与编译的结构。
    要使用这个选项࿰class="tags" href="/tags/C.html" title=c>c;可以在vclass="tags" href="/tags/C.html" title=c>c6中打开工程属性页࿰class="tags" href="/tags/C.html" title=c>c;class="tags" href="/tags/C.html" title=c>c/class="tags" href="/tags/C.html" title=c>c++页࿰class="tags" href="/tags/C.html" title=c>c;选择Code Generation分类࿰class="tags" href="/tags/C.html" title=c>c;在Struclass="tags" href="/tags/C.html" title=c>ct member class="tags" href="/tags/ALIGNMENT.html" title=alignment>alignment可以选择。

    要专门针对某些结构定义使用对齐选项࿰class="tags" href="/tags/C.html" title=c>c;可以使用#pragma paclass="tags" href="/tags/C.html" title=c>ck编译指令。指令语法如下:
#pragma paclass="tags" href="/tags/C.html" title=c>ck( [ show ] | [ push | pop ] [, identifier ] , n  )
    意义和/Zpn选项相同。比如:

    #pragma paclass="tags" href="/tags/C.html" title=c>ck(1)
    class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct foo_paclass="tags" href="/tags/C.html" title=c>ck
    {
        class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c1;
        short s;
        class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c2;
        int i;
    };
    #pragma paclass="tags" href="/tags/C.html" title=c>ck()

    栈内存对齐

    我们可以观察到࿰class="tags" href="/tags/C.html" title=c>c;在vclass="tags" href="/tags/C.html" title=c>c6中栈的对齐方式不受结构成员对齐选项的影响。(本来就是两码事)。它总是保持对齐࿰class="tags" href="/tags/C.html" title=c>c;而且对齐在4字节边界上。

    验证代码

    #inclass="tags" href="/tags/C.html" title=c>clude <stdio.h>

    class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct foo
    {
        class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c1;
        short s;
        class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c2;
        int i;
    };

    class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct bar
    {
        class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c1;
        class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c2;
        short s;
        int i;
    };

    #pragma paclass="tags" href="/tags/C.html" title=c>ck(1)
    class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct foo_paclass="tags" href="/tags/C.html" title=c>ck
    {
        class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c1;
        short s;
        class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c2;
        int i;
    };
    #pragma paclass="tags" href="/tags/C.html" title=c>ck()


    int main(int argclass="tags" href="/tags/C.html" title=c>c, class="tags" href="/tags/C.html" title=c>char* argv[])
    {
        class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c1;
        short s;
        class="tags" href="/tags/C.html" title=c>char class="tags" href="/tags/C.html" title=c>c2;
        int i;

    class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct foo a;
    class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct bar b;
    class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct foo_paclass="tags" href="/tags/C.html" title=c>ck p;

    printf("staclass="tags" href="/tags/C.html" title=c>ck class="tags" href="/tags/C.html" title=c>c1 %p, s %p, class="tags" href="/tags/C.html" title=c>c2 %p, i %p/n",
        (unsigned int)(void*)&class="tags" href="/tags/C.html" title=c>c1 - (unsigned int)(void*)&i,
        (unsigned int)(void*)&s - (unsigned int)(void*)&i,
        (unsigned int)(void*)&class="tags" href="/tags/C.html" title=c>c2 - (unsigned int)(void*)&i,
        (unsigned int)(void*)&i - (unsigned int)(void*)&i);

    printf("class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct foo class="tags" href="/tags/C.html" title=c>c1 %p, s %p, class="tags" href="/tags/C.html" title=c>c2 %p, i %p/n",
        (unsigned int)(void*)&a.class="tags" href="/tags/C.html" title=c>c1 - (unsigned int)(void*)&a,
        (unsigned int)(void*)&a.s - (unsigned int)(void*)&a,
        (unsigned int)(void*)&a.class="tags" href="/tags/C.html" title=c>c2 - (unsigned int)(void*)&a,
        (unsigned int)(void*)&a.i - (unsigned int)(void*)&a);

    printf("class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct bar class="tags" href="/tags/C.html" title=c>c1 %p, class="tags" href="/tags/C.html" title=c>c2 %p, s %p, i %p/n",
        (unsigned int)(void*)&b.class="tags" href="/tags/C.html" title=c>c1 - (unsigned int)(void*)&b,
        (unsigned int)(void*)&b.class="tags" href="/tags/C.html" title=c>c2 - (unsigned int)(void*)&b,
        (unsigned int)(void*)&b.s - (unsigned int)(void*)&b,
        (unsigned int)(void*)&b.i - (unsigned int)(void*)&b);

    printf("class="tags" href="/tags/C.html" title=c>class="tags" href="/tags/STRUCT.html" title=struclass="tags" href="/tags/C.html" title=c>ct>struclass="tags" href="/tags/C.html" title=c>ct foo_paclass="tags" href="/tags/C.html" title=c>ck class="tags" href="/tags/C.html" title=c>c1 %p, s %p, class="tags" href="/tags/C.html" title=c>c2 %p, i %p/n",
        (unsigned int)(void*)&p.class="tags" href="/tags/C.html" title=c>c1 - (unsigned int)(void*)&p,
        (unsigned int)(void*)&p.s - (unsigned int)(void*)&p,
        (unsigned int)(void*)&p.class="tags" href="/tags/C.html" title=c>c2 - (unsigned int)(void*)&p,
        (unsigned int)(void*)&p.i - (unsigned int)(void*)&p);

    printf("sizeof foo is %d/n", sizeof(foo));
    printf("sizeof bar is %d/n", sizeof(bar));
    printf("sizeof foo_paclass="tags" href="/tags/C.html" title=c>ck is %d/n", sizeof(foo_paclass="tags" href="/tags/C.html" title=c>ck));
   
    return 0;


    }

class="tags" href="/tags/C.html" title=c>cle>

http://www.niftyadmin.cn/n/1187015.html

相关文章

关于sizeof

http://www.360doc.com/content/10/0124/00/722458_14261259.shtml 为了能使CPU对变量进行高效快速的访问&#xff0c;变量的起始地址应该具有某些特性&#xff0c;即所谓的“对齐”。例如对于4字节的int类型变量&#xff0c;其起始地址应位于4字节边界上&#xff0c;即起始地…

go的中间件

package mainimport ("fmt""github.com/gin-gonic/gin""log""net/http" )func middleware1() gin.HandlerFunc{return func (c *gin.Context){log.Print("middleware1-1")c.Next()//执行到此处&#xff0c;就跳转到下一个函…

为什么说直到出现中断和通道技术后,多道程序概念才变为有用的?

为什么说直到出现中断和通道技术后&#xff0c;多道程序概念才变为有用的&#xff1f; 转载自http://hi.baidu.com/litteice/blog/item/7fc9e9dcaebae7a1cc1166cb.html 采用多道程序设计减少了CPU时间的浪费&#xff0c;增加了系统吞吐量&#xff0c;提高了系统的效率。多道程…

图像处理笔记(十九):分类器之高斯混合模型

关于模板匹配的一个小补充&#xff1a; 做了一个很小型的模板匹配用于缺陷检测的应用&#xff0c;测试结果发现模板使用锐化后叠加原图的图片效果会比较好。 测试过程同样存在图片数量不足的问题。 模板匹配针对缺陷可能存在多种不同形态的检测不合适。 发现一个现象&#xff0…

C++ socket程序

转自http://hereson.javaeye.com/blog/198771下面是一个C调用windows API实现有通信程序,您可以据此进行修改,封装成类.// *******************************************************************// client.cpp : Defines the entry point for the console application.// ****…

二叉树三种非递归遍历实现

二叉树三种非递归遍历实现http://mcs.sysu.edu.cn/user/longt/Article_1781| 浏览数(1022) | 评论数(0) | 2009-10-17继续回顾基础三种遍历的非递归实现要点&#xff1a;利用栈&#xff0c;把握好进栈顺序&#xff0c;做好标记。~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~测试…

mysql条件插入

#新建表 create table t_user ( userNamevarchar(100), gender varchar(2) ) #带条件插入&#xff0c;如果表中没有userNamename1的记录&#xff0c;就插入&#xff0c;否则就不插入 insert into t_userselect name1,Mfrom DUALwhere not exists( select userName #这里是sele…

有了malloc/free为什么还要new/delete?

来自: http://hi.baidu.com/sppeivan/blog/item/3041ca0e7c3d39206059f3ba.html malloc与free是C/C语言的标准库函数&#xff0c;new/delete是C的运算符。它们都可用于申请动态内存和释放内存。 对于非内部数据类型的对象而言&#xff0c;光用maloc/free无法满足动态对象的要…