﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-海子海-最新评论</title><link>http://www.cppblog.com/fangzdi/CommentsRSS.aspx</link><description>胆大能吃苦有钱没文化</description><language>zh-cn</language><pubDate>Mon, 15 Sep 2008 07:17:38 GMT</pubDate><lastBuildDate>Mon, 15 Sep 2008 07:17:38 GMT</lastBuildDate><generator>cnblogs</generator><item><title>re:  #pragma pack(n)转的</title><link>http://www.cppblog.com/fangzdi/archive/2008/09/15/61867.html#61868</link><dc:creator>海子海</dc:creator><author>海子海</author><pubDate>Mon, 15 Sep 2008 07:27:00 GMT</pubDate><guid>http://www.cppblog.com/fangzdi/archive/2008/09/15/61867.html#61868</guid><description><![CDATA[为了能使CPU对变量进行高效快速的访问，变量的起始地址应该具有某些特性，即所谓的“对齐”。例如对于4字节的int类型变量，其起始地址应位于4字节边界上，即起始地址能够被4整除。变量的对齐规则如下（32位系统）：<br>Type<br>Alignment<br>char<br>在字节边界上对齐<br>short (16-bit)<br>在双字节边界上对齐<br>int and long (32-bit)<br>在4字节边界上对齐<br>float<br>在4字节边界上对齐<br>double<br>在8字节边界上对齐<br>structures<br>单独考虑结构体的个成员，它们在不同的字节边界上对齐。<br>其中最大的字节边界数就是该结构的字节边界数。<br><br>如果结构体中有结构体成员，那么这是一个递归的过程。<br>设编译器设定的最大对齐字节边界数为n，对于结构体中的某一成员item，它相对于结构首地址的实际字节对齐数<br><br>目X应该满足以下规则：<br>X = min(n, sizeof(item))<br>例如，对于结构体<br>struct {<br>char a;<br>long b;<br>} T;<br>当位于32位系统，n=8时：<br>a的偏移为0，<br>b的偏移为4，中间填充了3个字节, b的X为4；<br><br>当位于32位系统，n=2时：<br>a的偏移为0，<br>b的偏移为2，中间填充了1个字节，b的X为2；<br>结构体的sizeof:<br>设结构体的最后一个成员为LastItem，其相对于结构体首地址的偏移为offset（LastItem），其大小为sizeof(LastItem)，结构体的字节对齐数为N，则：结构体的sizeof 为： 若offset（LastItem）＋ sizeof(LastItem)能够被N整除，那么就是offset（LastItem）＋ sizeof(LastItem)，否则，在后面填充，直到能够被N整除。<br>另外:<br>1） 对于空结构体，sizeof ＝＝ 1；因为必须保证结构体的每一个实例在内存中都有独一无二的地址.<br>2）结构体的静态成员不对结构体的大小产生影响，因为静态变量的存储位置与结构体的实例地址无关。例如：<br>struct {static int I;} T; struct {char a; static int I;} T1;<br>sizeof(T) == 1; sizeof(T1) == 1;<br><br><br>下面是CSDN上提出的问题(原文&lt;&gt;:<a target="_new" href="http://community.csdn.net/Expert/TopicView3.asp?id=3804035">http://community.csdn.net/Expert/TopicView3.asp?id=3804035</a>)<br>---------------------------------------<br>#pragma pack(8)<br><br>struct s1{<br>short a;<br>long b;<br>};<br><br>struct s2{<br>char c;<br>s1 d;<br>long long e;<br>};<br><br>#pragma pack()<br><br>问<br>1.sizeof(s2) = ?<br>2.s2的c后面空了几个字节接着是d?<br>---------------------------------------<br><br>下面是redleaves(ID最吊的网友)给出的解释:<br>很详尽,很透彻,从论坛原文后头的对话可以看出redleaves对C/C++的标准理解很深刻,值得偶学习:)<br>#pragma pack(8)<br>struct S1{<br>char a;<br>long b;<br>};<br>struct S2 {<br>char c;<br>struct S1 d;<br>long long e;<br>};<br>#pragma pack()<br>sizeof(S2)结果为24.<br>成员对齐有一个重要的条件,即每个成员分别对齐.即每个成员按自己的方式对齐.<br>也就是说上面虽然指定了按8字节对齐,但并不是所有的成员都是以8字节对齐.其对齐的规则是,每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里是8字节)中较小的一个对齐.并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节.<br>S1中,成员a是1字节默认按1字节对齐,指定对齐参数为8,这两个值中取1,a按1字节对齐;成员b是4个字节,默认是按4字节对齐,这时就按4字节对齐,所以sizeof(S1)应该为8;<br>S2 中,c和S1中的a一样,按1字节对齐,而d 是个结构,它是8个字节,它按什么对齐呢?对于结构来说,它的默认对齐方式就是它的所有成员使用的对齐参数中最大的一个,S1的就是4.所以,成员d就是按4字节对齐.成员e是8个字节,它是默认按8字节对齐,和指定的一样,所以它对到8字节的边界上,这时,已经使用了12个字节了,所以又添加了4个字节的空,从第16个字节开始放置成员e.这时,长度为24,已经可以被8(成员e按8字节对齐)整除.这样,一共使用了24个字节.<br>a b<br>S1的内存布局：11**,1111,<br>c S1.a S1.b d<br>S2的内存布局：1***,11**,1111,****11111111<br><br>这里有三点很重要:<br>1.每个成员分别按自己的方式对齐,并能最小化长度<br>2.复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度<br>3.对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐<br><br>对于数组,比如:<br>char a[3];这种,它的对齐方式和分别写3个char是一样的.也就是说它还是按1个字节对齐.<br>如果写: typedef char Array3[3];<br>Array3这种类型的对齐方式还是按1个字节对齐,而不是按它的长度.<br>不论类型是什么,对齐的边界一定是1,2,4,8,16,32,64....中的一个.<br><br>如下一段代码：<br>　　#pragma pack(4)<br>　　class TestB<br>　　{<br>　　public:<br>　　　　int aa;<br>　　　　char a;<br>　　　　short b;<br>　　　　char c;<br>　　};<br>　　int nSize = sizeof(TestB);<br>　　这里nSize结果为12，在预料之中。<br><br>　　现在去掉第一个成员变量为如下代码：<br>　　#pragma pack(4)<br>　　class TestC<br>　　{<br>　　public:<br>　　　　char a;<br>　　　　short b;<br>　　　　char c;<br>　　};<br>　　int nSize = sizeof(TestC);<br>　　按照正常的填充方式nSize的结果应该是8，为什么结果显示nSize为6呢？<br><br>事实上，很多人对#pragma pack的理解是错误的。<br>#pragma pack规定的对齐长度，实际使用的规则是：<br>结构，联合，或者类的数据成员，第一个放在偏移为0的地方，以后每个数据成员的对齐，按照#pragma pack指定的数值和这个数据成员自身长度中，比较小的那个进行。<br>也就是说，当#pragma pack的值等于或超过所有数据成员长度的时候，这个值的大小将不产生任何效果。<br>而结构整体的对齐，则按照结构体中最大的数据成员和 #pragma pack指定值 之间，较小的那个进行。<br><br>具体解释<br>#pragma pack(4)<br>　　class TestB<br>　　{<br>　　public:<br>　　　　int aa; //第一个成员，放在[0,3]偏移的位置，<br>　　　　char a; //第二个成员，自身长为1，#pragma pack(4),取小值，也就是1，所以这个成员按一字节对齐，放在偏移[4]的位置。<br>　　　　short b; //第三个成员，自身长2，#pragma pack(4)，取2，按2字节对齐，所以放在偏移[6,7]的位置。<br>　　　　char c; //第四个，自身长为1，放在[8]的位置。<br>　　};<br>这个类实际占据的内存空间是9字节<br>类之间的对齐，是按照类内部最大的成员的长度，和#pragma pack规定的值之中较小的一个对齐的。<br>所以这个例子中，类之间对齐的长度是min(sizeof(int),4)，也就是4。<br>9按照4字节圆整的结果是12，所以sizeof(TestB)是12。<br><br><br>如果<br>#pragma pack(2)<br>class TestB<br>　　{<br>　　public:<br>　　　　int aa; //第一个成员，放在[0,3]偏移的位置，<br>　　　　char a; //第二个成员，自身长为1，#pragma pack(4),取小值，也就是1，所以这个成员按一字节对齐，放在偏移[4]的位置。<br>　　　　short b; //第三个成员，自身长2，#pragma pack(4)，取2，按2字节对齐，所以放在偏移[6,7]的位置。<br>　　　　char c; //第四个，自身长为1，放在[8]的位置。<br>　　};<br>//可以看出，上面的位置完全没有变化，只是类之间改为按2字节对齐，9按2圆整的结果是10。<br>//所以 sizeof(TestB)是10。<br><br>最后看原贴：<br>现在去掉第一个成员变量为如下代码：<br>　　#pragma pack(4)<br>　　class TestC<br>　　{<br>　　public:<br>　　　　char a;//第一个成员，放在[0]偏移的位置，<br>　　　　short b;//第二个成员，自身长2，#pragma pack(4)，取2，按2字节对齐，所以放在偏移[2,3]的位置。<br>　　　　char c;//第三个，自身长为1，放在[4]的位置。<br>　　};<br>//整个类的大小是5字节，按照min(sizeof(short),4)字节对齐，也就是2字节对齐，结果是6<br>//所以sizeof(TestC)是6。<br><br>感谢 Michael 提出疑问，在此补充：<br><br>当数据定义中出现__declspec( align() )时，指定类型的对齐长度还要用自身长度和这里指定的数值比较，然后取其中较大的。最终类/结构的对齐长度也需要和这个数值比较，然后取其中较大的。<br><br>可以这样理解， __declspec( align() ) 和 #pragma pack是一对兄弟，前者规定了对齐的最小值，后者规定了对齐的最大值，两者同时出现时，前者拥有更高的优先级。<br>__declspec ( align() )的一个特点是，它仅仅规定了数据对齐的位置，而没有规定数据实际占用的内存长度，当指定的数据被放置在确定的位置之后，其后的数据填充仍然是按照#pragma pack规定的方式填充的，这时候类/结构的实际大小和内存格局的规则是这样的：<br>在__declspec( align () )之前，数据按照#pragma pack规定的方式填充，如前所述。当遇到__declspec( align() )的时候，首先寻找距离当前偏移向后最近的对齐点（满足对齐长度为 max(数据自身长度,指定值) )，然后把被指定的数据类型从这个点开始填充，其后的数据类型从它的后面开始，仍然按照#pragma pack填充，直到遇到下一个__declspec( align() )。<br>当所有数据填充完毕，把结构的整体对齐数值和__declspec( align() )规定的值做比较，取其中较大的作为整个结构的对齐长度。<br>特别的，当__declspec( align() )指定的数值比对应类型长度小的时候，这个指定不起作用。<br><img src ="http://www.cppblog.com/fangzdi/aggbug/61868.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/fangzdi/" target="_blank">海子海</a> 2008-09-15 15:27 <a href="http://www.cppblog.com/fangzdi/archive/2008/09/15/61867.html#61868#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>