• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            牽著老婆滿街逛

            嚴以律己,寬以待人. 三思而后行.
            GMail/GTalk: yanglinbo#google.com;
            MSN/Email: tx7do#yahoo.com.cn;
            QQ: 3 0 3 3 9 6 9 2 0 .

            字節(jié)對齊(強制對齊以及自然對齊)

            轉(zhuǎn)載自:http://www.cnblogs.com/alfredzzj/archive/2012/06/17/2552431.html

            struct {}node;

            32為的x86,window下VC下sizeof(node)的值為1,而linux的gcc下值為0;


            一、WINDOWS下(VC--其實GCC和其原理基本一樣,象這種問題,一般要查具體的編譯器設置)字節(jié)對齊的規(guī)則:

            1、一般設置的對齊方式為1,2,4字節(jié)對齊方式,VC一般默認為4字節(jié)(最大為8字節(jié))。結(jié)構(gòu)的首地址必須是結(jié)構(gòu)內(nèi)最寬類型的整數(shù)倍地址;另外,結(jié)構(gòu)體的每一個成員起始地址必須是自身類型大小的整數(shù)倍(需要特別注意的是windows下是這樣的,但在linux的gcc編譯器下最高為4字節(jié)對齊),否則在前一類型后補0;這里特別提到的是數(shù)組一定要注意,而且在一些編程的技巧中,我們可以使用數(shù)組強制字節(jié)達到對齊的目的。這在網(wǎng)絡編程中是很常見的。

            舉例:比如CHAR型占用空間為1字節(jié),則其起始位置必須可被1整除。INT為4字節(jié),其起始位置必須被4帶隊,依次類推。(我們假定類或結(jié)構(gòu)體的起始位置為0位置,其實編譯器是在開辟空間時,會尋找起始位置可被結(jié)構(gòu)內(nèi)最寬類型整除的地址做為開始地址,因此我們可以假定其為0值,因為這0值可以被任意的類型整除。)

            2、結(jié)構(gòu)體的整體大小必須可被對齊值整除,默認4(默認,且結(jié)構(gòu)中的類型大小都小于默認的4)。

            3、結(jié)構(gòu)體的整體大小必須可被本結(jié)構(gòu)內(nèi)的最寬類型整除。(其實和上一條是一樣的,但這里獨立出來,起注意作用。比如結(jié)構(gòu)體里的有DOUBLE,那么結(jié)構(gòu)的大小最后必須可被8整除)

            注意:GCC不是這樣,就是最高只能被4整除,它是個死的。

            否則(2、3條),編譯器會在結(jié)構(gòu)的最后添充一定的特定字符來補齊。

            struct T 
            { 
            char ch; 
            double d ; 
            };

            在VC中是16個字節(jié),GCC中為12個字節(jié)。

            4、對于結(jié)構(gòu)體內(nèi)嵌套結(jié)構(gòu)體的形勢,規(guī)定是必須按照基本數(shù)據(jù)類型來定義,而不能以嵌套結(jié)構(gòu)大小來做為上三種使用的基準。

            二、舉例:

            struct A 
            { 
            int a; 
            char b; 
            short c; 
            }; 
            struct B 
            { 
            char b; 
            int a; 
            short c; 
            }; 
            struct C 
            { 
            double t; 
            char b; 
            int a; 
            short c; 
            }; 
            struct D 
            { 
            char b; 
            double t; 
            int a; 
            short c; 
            };

            在VC中,SIZEOF這四個結(jié)構(gòu)體,分別為:8、12、24、24;

            我們先談第一個,(說明一下,在考慮結(jié)構(gòu)體大小時,我們基本可以忽略起始地址的問題,因為這個編譯器會自動為我們做好,見上面的說明),結(jié)構(gòu)體內(nèi)首先是一個INT的4字節(jié),起始地址假定為0,整除4,其小于等于默認的4字節(jié)對齊且0為4(INT的占用空間)的整數(shù)倍,所以,其占四個字節(jié);其后為起始地址為5,空間為1個字節(jié)的CHAR,小于4且5為1(CHAR占用空間)的整數(shù)倍,故占用1個字節(jié),然后是一個起始地址為5占2個字節(jié)的SHORT,其小于4,但5不為2位數(shù),故補齊一個字節(jié),從第6個字節(jié)開始,占2字節(jié)空間。所以共占用4+1+1(補)+2=8;8/4=2;整除,故占用8字節(jié)空間。

            再談第2個,CHAR不用解釋,占有一個字節(jié)空間,且可以被0地址整除。而INT則占4字節(jié)空間,所以其必須在CHAR后補齊3字節(jié),到第四個字節(jié),才是INT的真正地址。SHORT也不用說,所以共占有:1+3(補)+4+2=10個字節(jié),但10不能整除4,所以要在結(jié)構(gòu)體最后補齊2字節(jié)。故實際占有10+2= 12個字節(jié)。

            談第三個,C結(jié)構(gòu)體只是在B結(jié)構(gòu)體前加了一個DOUBLE,其它都一樣,按說應該是20個字節(jié)啊,但注意我們上面規(guī)則的第3條。必須是最寬類型的整數(shù)倍,一定要分清,所以得補齊到24,D結(jié)構(gòu)體類似,不再講。

            三、結(jié)構(gòu)體的中含有位域

            這個東西用得比較少,但還是總結(jié)一下:

            如果結(jié)構(gòu)體中含有位域(bit-field),那么VC中準則又要有所更改: 
            1) 如果相鄰位域字段的類型相同,且其位寬之和小于類型的sizeof大小,則后面的字段將緊鄰前一個字段存儲,直到不能容納為止; 
            2) 如果相鄰位域字段的類型相同,但其位寬之和大于類型的sizeof大小,則后面的字段將從新的存儲單元開始,其偏移量為其類型大小的整數(shù)倍; 
            3) 如果相鄰的位域字段的類型不同,則各編譯器的具體實現(xiàn)有差異,VC6采取不壓縮方式(不同位域字段存放在不同的位域類型字節(jié)中),Dev-C++和GCC都采取壓縮方式; 
            備注:當兩字段類型不一樣的時候,對于不壓縮方式,例如:

            struct N 
            { 
            char c:2; 
            int i:4; 
            };

            依然要滿足不含位域結(jié)構(gòu)體內(nèi)存對齊準則第2條,i成員相對于結(jié)構(gòu)體首地址的偏移應該是4的整數(shù)倍,所以c成員后要填充3個字節(jié),然后再開辟4個字節(jié)的空間作為int型,其中4位用來存放i,所以上面結(jié)構(gòu)體在VC中所占空間為8個字節(jié);而對于采用壓縮方式的編譯器來說,遵循不含位域結(jié)構(gòu)體內(nèi)存對齊準則第2條,不同的是,如果填充的3個字節(jié)能容納后面成員的位,則壓縮到填充字節(jié)中,不能容納,則要單獨開辟空間,所以上面結(jié)構(gòu)體N在GCC或者Dev-C++中所占空間應該是4個字節(jié)。

            4) 如果位域字段之間穿插著非位域字段,則不進行壓縮; 
            備注: 
            結(jié)構(gòu)

            typedef struct 
            { 
            char c:2; 
            double i; 
            int c2:4; 
            }N3;

            在GCC下占據(jù)的空間為16字節(jié),在VC下占據(jù)的空間應該是24個字節(jié)。

            四、字節(jié)對齊的控制方法

            主要是使用:

            #pragma pack (2) /*指定按2字節(jié)對齊*/ 
            struct C 
            { 
            char b; 
            int a; 
            short c; 
            }; 
            #pragma pack () /*取消指定對齊,恢復缺省對齊*/

            大家如果有興趣,可以自己上機調(diào)一下各種對齊方式下的占用空間大小,這里就不再舉例。

            #pragma pack(push) //保存對齊狀態(tài) 
            #pragma pack(4)//設定為4字節(jié)對齊 
            struct test 
            { 
            char m1; 
            double m4; 
            int m3; 
            }; 
            #pragma pack(pop)//恢復對齊狀態(tài)

            這里需要注意的是,如果對齊的字節(jié)非為1、2、4、8等可整除位數(shù),則自動默認回默認的對齊字節(jié)數(shù),這個我沒有測試,大家可以試一下,應該沒什么問題。

            五、多編譯器的使用:(其下為轉(zhuǎn)載

            為了防止不同編譯器對齊不一樣,建議在代碼里面指定對齊參數(shù)

            可能重要的一點是關于緊縮結(jié)構(gòu)的。緊縮結(jié)構(gòu)的用途 其實最常用的結(jié)構(gòu)對齊選項就是:默認對齊和緊縮。在兩個程序,或者兩個平臺之間傳遞數(shù)據(jù)時,我們通常會將數(shù)據(jù)結(jié)構(gòu)設置為緊縮的。這樣不僅可以減小通信量,還可以避免對齊帶來的麻煩。假設甲乙雙方進行跨平臺通信,甲方使用了“/Zp2”這么奇怪的對齊選項,而乙方的編譯器不支持這種對齊方式,那么乙方就可以理解什么叫欲哭無淚了。 當我們需要一個字節(jié)一個字節(jié)訪問結(jié)構(gòu)數(shù)據(jù)時,我們通常都會希望結(jié)構(gòu)是緊縮的,這樣就不必考慮哪個字節(jié)是填充字節(jié)了。我們把數(shù)據(jù)保存到非易失設備時,通常也會采用緊縮結(jié)構(gòu),既減小存儲量,也方便其它程序讀出。各編譯器都支持結(jié)構(gòu)的緊縮,即連續(xù)排列結(jié)構(gòu)的各成員變量,各成員變量之間沒有任何填充字節(jié)。這時,結(jié)構(gòu)的大小等于各成員變量大小的和。緊縮結(jié)構(gòu)的變量可以放在1n邊界,即任意地址邊界。在GNU gcc:

            typedef struct St2Tag

            {

            St1 st1;

            char ch2;

            }

            __attribute__ ((packed)) St2;

            在ARMCC:

            typedef __packed struct St2Tag

            {

            St1 st1;

            char ch2;

            } St2;

            在VC:

            #pragma pack(1)

            typedef struct St2Tag

            {

            St1 st1;

            char ch2;

            } St2;

            #pragma pack()

            針對不同的編譯器:

            #ifdef __GNUC__

            #define GNUC_PACKED __attribute__ ((packed))

            #else

            #define GNUC_PACKED

            #endif

            #ifdef __arm

            #define ARM_PACKED __packed

            #else

            #define ARM_PACKED

            #endif

            #ifdef WIN32

            #pragma pack(1)

            #endif

            typedef ARM_PACKED struct St2Tag

            {

            St1 st1;

            char ch2;

            }

            GNUC_PACKED St2;

            #ifdef WIN32

            #pragma pack()

            #endif

            最后記錄一個小細節(jié)。gcc編譯器和VC編譯器都支持在緊縮結(jié)構(gòu)中包含非緊縮結(jié)構(gòu),例如前面例子中的St2可以包含非緊縮的St1。但對于ARM編譯器而言,緊縮結(jié)構(gòu)包含的其它結(jié)構(gòu)必須是緊縮的。如果緊縮的St2包含了非緊縮的St1,編譯時就會報錯:

             

             

             

             

            C語言的字節(jié)對齊及#pragma pack的使用

            2010-04-16 09:44:33| 分類: vc/c/c++ | 標簽: |字號大中小 訂閱

            C編譯器的缺省字節(jié)對齊方式(自然對界)

            在缺省情況下,C編譯器為每一個變量或是數(shù)據(jù)單元按其自然對界條件分配空間。

            在結(jié)構(gòu)中,編譯器為結(jié)構(gòu)的每個成員按其自然對界(alignment)條件分配空間。各個成員按照它們被聲明的順序在內(nèi)存中順序存儲(成員之間可能有插入的空字節(jié)),第一個成員的地址和整個結(jié)構(gòu)的地址相同。

            C編譯器缺省的結(jié)構(gòu)成員自然對界條件為“N字節(jié)對齊”,N即該成員數(shù)據(jù)類型的長度。如int型成員的自然對界條件為4字節(jié)對齊,而double類型的結(jié)構(gòu)成員的自然對界條件為8字節(jié)對齊。若該成員的起始偏移不位于該成員的“默認自然對界條件”上,則在前一個節(jié)面后面添加適當個數(shù)的空字節(jié)。

            C編譯器缺省的結(jié)構(gòu)整體的自然對界條件為:該結(jié)構(gòu)所有成員中要求的最大自然對界條件。若結(jié)構(gòu)體各成員長度之和不為“結(jié)構(gòu)整體自然對界條件的整數(shù)倍,則在最后一個成員后填充空字節(jié)。

            例子1(分析結(jié)構(gòu)各成員的默認字節(jié)對界條界條件和結(jié)構(gòu)整體的默認字節(jié)對界條件):

            struct Test
            {
            char x1; // 成員x1為char型(其起始地址必須1字節(jié)對界),其偏移地址為0

            char x2; // 成員x2為char型(其起始地址必須1字節(jié)對界,其偏移地址為1

            float x3; // 成員x3為float型(其起始地址必須4字節(jié)對界),編譯器在x2和x3之間填充了兩個空字節(jié),其偏移地址為4

            char x4; // 成員x4為char型(其起始地址必須1字節(jié)對界),其偏移地址為8
            };

            因為Test結(jié)構(gòu)體中,最大的成員為flaot x3,因些此結(jié)構(gòu)體的自然對界條件為4字節(jié)對齊。則結(jié)構(gòu)體長度就為12字節(jié),內(nèi)存布局為1100 1111 1000。

            例子2:

            #include <stdio.h>
            //#pragma pack(2)
            typedef struct
            {
            int aa1; //4個字節(jié)對齊 1111
            char bb1;//1個字節(jié)對齊 1
            short cc1;//2個字節(jié)對齊 011
            char dd1; //1個字節(jié)對齊 1
            } testlength1;
            int length1 = sizeof(testlength1); //4個字節(jié)對齊,占用字節(jié)1111 1011 1000,length = 12

            typedef struct
            {
            char bb2;//1個字節(jié)對齊 1
            int aa2; //4個字節(jié)對齊 01111
            short cc2;//2個字節(jié)對齊 11
            char dd2; //1個字節(jié)對齊 1
            } testlength2;
            int length2 = sizeof(testlength2); //4個字節(jié)對齊,占用字節(jié)1011 1111 1000,length = 12


            typedef struct
            {
            char bb3; //1個字節(jié)對齊 1
            char dd3; //1個字節(jié)對齊 1
            int aa3; //4個字節(jié)對齊 001111
            short cc23//2個字節(jié)對齊 11

            } testlength3;
            int length3 = sizeof(testlength3); //4個字節(jié)對齊,占用字節(jié)1100 1111 1100,length = 12


            typedef struct
            {
            char bb4; //1個字節(jié)對齊 1
            char dd4; //1個字節(jié)對齊 1
            short cc4;//2個字節(jié)對齊 11
            int aa4; //4個字節(jié)對齊 1111
            } testlength4;
            int length4 = sizeof(testlength4); //4個字節(jié)對齊,占用字節(jié)1111 1111,length = 8


            int main(void)
            {
            printf("length1 = %d.\n",length1);
            printf("length2 = %d.\n",length2);
            printf("length3 = %d.\n",length3);
            printf("length4 = %d.\n",length4);
            return 0;
            }

            改變?nèi)笔〉膶鐥l件(指定對界) 
            · 使用偽指令#pragma pack (n),C編譯器將按照n個字節(jié)對齊。 
            · 使用偽指令#pragma pack (),取消自定義字節(jié)對齊方式。

            這時,對齊規(guī)則為:

            1、數(shù)據(jù)成員對齊規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union))的數(shù)據(jù)成員,第一個數(shù)據(jù)成員放在offset為0的地方,以后每個數(shù)據(jù)成員的對齊按照#pragma pack指定的數(shù)值和這個數(shù)據(jù)成員自身長度中,比較小的那個進行。

            2、結(jié)構(gòu)(或聯(lián)合)的整體對齊規(guī)則:在數(shù)據(jù)成員完成各自對齊之后,結(jié)構(gòu)(或聯(lián)合)本身也要進行對齊,對齊將按照#pragma pack指定的數(shù)值和結(jié)構(gòu)(或聯(lián)合)最大數(shù)據(jù)成員長度中,比較小的那個進行。

            結(jié)合1、2推斷:當#pragma pack的n值等于或超過所有數(shù)據(jù)成員長度的時候,這個n值的大小將不產(chǎn)生任何效果。

            因此,當使用偽指令#pragma pack (2)時,Test結(jié)構(gòu)體的大小為8,內(nèi)存布局為11 11 11 10。

            需要注意一點,當結(jié)構(gòu)體中包含一個子結(jié)構(gòu)體時,子結(jié)構(gòu)中的成員按照#pragma pack指定的數(shù)值和子結(jié)構(gòu)最大數(shù)據(jù)成員長度中,比較小的那個進行進行對齊。例子如下:

            #pragma pack(8) 
            struct s1{ 
            short a; 
            long b; 
            };

            struct s2{ 
            char c; 
            s1 d; 
            long long e; 
            }; 
            #pragma pack()

            sizeof(s2)的結(jié)果為24。S1的內(nèi)存布局為1100 1111,S2的內(nèi)存布局為1000 1100 1111 0000 1111 1111。

            例子:

            #include <stdio.h>
            #pragma pack(2)
            typedef struct
            {
            int aa1; //2個字節(jié)對齊 1111
            char bb1;//1個字節(jié)對齊 1
            short cc1;//2個字節(jié)對齊 011
            char dd1; //1個字節(jié)對齊 1
            } testlength1;
            int length1 = sizeof(testlength1); //2個字節(jié)對齊,占用字節(jié)11 11 10 11 10,length = 10

            typedef struct
            {
            char bb2;//1個字節(jié)對齊 1
            int aa2; //2個字節(jié)對齊 01111
            short cc2;//2個字節(jié)對齊 11
            char dd2; //1個字節(jié)對齊 1
            } testlength2;
            int length2 = sizeof(testlength2); //2個字節(jié)對齊,占用字節(jié)10 11 11 11 10,length = 10


            typedef struct
            {
            char bb3; //1個字節(jié)對齊 1
            char dd3; //1個字節(jié)對齊 1
            int aa3; //2個字節(jié)對齊 11 11
            short cc23//2個字節(jié)對齊 11

            } testlength3;
            int length3 = sizeof(testlength3); //2個字節(jié)對齊,占用字節(jié)11 11 11 11,length = 8


            typedef struct
            {
            char bb4; //1個字節(jié)對齊 1
            char dd4; //1個字節(jié)對齊 1
            short cc4;//2個字節(jié)對齊 11
            int aa4; //2個字節(jié)對齊 11 11
            } testlength4;
            int length4 = sizeof(testlength4); //2個字節(jié)對齊,占用字節(jié)11 11 11 11,length = 8


            int main(void)
            {
            printf("length1 = %d.\n",length1);
            printf("length2 = %d.\n",length2);
            printf("length3 = %d.\n",length3);
            printf("length4 = %d.\n",length4);
            return 0;
            }

            另外,還有如下的一種方式:

            · __attribute((aligned (n))),讓所作用的結(jié)構(gòu)成員對齊在n字節(jié)自然邊界上。如果結(jié)構(gòu)中有成員的長度大于n,則按照最大成員的長度來對齊。

            · __attribute__ ((packed)),取消結(jié)構(gòu)在編譯過程中的優(yōu)化對齊,按照實際占用字節(jié)數(shù)進行對齊。

            以上的n = 1, 2, 4, 8, 16... 第一種方式較為常見。


            posted on 2014-04-17 15:43 楊粼波 閱讀(1031) 評論(0)  編輯 收藏 引用 所屬分類: C++

            久久婷婷成人综合色综合| 亚洲va久久久噜噜噜久久天堂| 狠狠色丁香久久婷婷综合图片 | 无码任你躁久久久久久老妇| 日本高清无卡码一区二区久久 | 久久亚洲欧美国产精品| 久久久久久久97| 久久国产精品二国产精品| 热久久最新网站获取| 精品综合久久久久久97超人 | 三级三级久久三级久久 | 亚洲伊人久久大香线蕉苏妲己| 久久国产香蕉一区精品| 欧美丰满熟妇BBB久久久| 国产精品99久久久久久猫咪| 久久国产色av免费看| 亚洲狠狠婷婷综合久久久久| 婷婷久久综合九色综合九七| 国产成人精品久久| 久久一区二区三区免费| 亚洲国产成人久久精品影视| 久久天天躁狠狠躁夜夜2020老熟妇| 久久人妻无码中文字幕| 亚洲伊人久久成综合人影院 | 久久九九亚洲精品| 久久久久久久久久久久久久| 国产精品视频久久久| 99久久国产综合精品五月天喷水| 无码人妻久久一区二区三区免费 | 久久精品综合一区二区三区| 国产精品久久国产精麻豆99网站 | 狠狠色丁香久久综合五月| 国产∨亚洲V天堂无码久久久| 久久精品国产亚洲一区二区| 国产99精品久久| 精品久久一区二区三区| 国产精品99久久久久久猫咪| 国产日韩欧美久久| 精品久久久中文字幕人妻| 久久99热这里只有精品国产| 亚洲国产成人久久综合一 |