最近調(diào)試網(wǎng)絡(luò)的服務(wù)端程序,自己寫(xiě)了一個(gè)小客戶(hù)端程序來(lái)測(cè)試,發(fā)現(xiàn)服務(wù)程序解包錯(cuò)誤。經(jīng)調(diào)試發(fā)現(xiàn)客戶(hù)端的協(xié)議頭大小和服務(wù)器端的協(xié)議頭大小不一致。原因是服務(wù)器端加了#pragma pack(1),而客戶(hù)端沒(méi)加。
之前沒(méi)接觸過(guò)這個(gè)編譯宏,現(xiàn)在來(lái)認(rèn)真學(xué)習(xí)之。
首先google之~~
原來(lái)#pragma pack有幾種形式,我所接觸到的是#pragma pack(n),即變量以n字節(jié)對(duì)齊。
變量對(duì)齊在每個(gè)系統(tǒng)中是不一樣的,默認(rèn)的對(duì)齊方式能有效的提高cpu取指取數(shù)的速度,但是可能會(huì)浪費(fèi)一定的空間。在網(wǎng)絡(luò)程序中采用#pragma pack(1),即變量緊縮,不但可以減少網(wǎng)絡(luò)流量,還可以兼容各種系統(tǒng),不會(huì)因?yàn)橄到y(tǒng)對(duì)齊方式不同而導(dǎo)致解包錯(cuò)誤。
了解了概念和優(yōu)點(diǎn),現(xiàn)在我們就來(lái)測(cè)試之~
平臺(tái):CPU—Pentium E5700 內(nèi)存—2G
1.操作系統(tǒng):ubuntu 11.04 32bit 編譯器:G++ 4.5.2
2.操作系統(tǒng):windows xp 編譯器:VS2010
先看第一個(gè)測(cè)試。
結(jié)構(gòu)體在正常情況和緊縮情況在以上不同環(huán)境下占用的內(nèi)存大小。
1 struct pack {
2 int i;
3 short s;
4 double d;
5 char c;
6 short f;
7 }
測(cè)試結(jié)果為:
1:

2:

測(cè)試結(jié)果分析:
可以看出緊縮后結(jié)構(gòu)體的大小為15,是結(jié)構(gòu)體內(nèi)置類(lèi)型大小的和。但是在默認(rèn)情況下,結(jié)構(gòu)體的大小都是對(duì)齊字節(jié)數(shù)的倍數(shù)。ubuntu下pack只需要20個(gè)字節(jié),而windows要24個(gè)字節(jié)。這是因?yàn)?/span>ubuntu是以4字節(jié)對(duì)齊,而windows則是以最大的內(nèi)置類(lèi)型的字節(jié)數(shù)對(duì)齊,在結(jié)構(gòu)體內(nèi)最大的內(nèi)置類(lèi)型為double,其大小為8個(gè)字節(jié)。他們?cè)趦?nèi)存中的對(duì)齊方式如下圖:
1:

2:

還需注意的是,在對(duì)齊類(lèi)型的內(nèi)部都是以2字節(jié)對(duì)齊的。
結(jié)論:在默認(rèn)情況下,linux操作系統(tǒng)是以4字節(jié)對(duì)齊,windows操作系統(tǒng)則是以最大的內(nèi)置類(lèi)型對(duì)齊。
第二個(gè)測(cè)試
一個(gè)結(jié)構(gòu)體內(nèi)包含另外一個(gè)結(jié)構(gòu)體,其大小的情況。
內(nèi)部的結(jié)構(gòu)體為
1 struct pack {
2 short s;
3 double d;
4 }
外部的結(jié)構(gòu)體為
1 struct complex _pack{
2 char c;
3 struct pack s;
4 double d;
5 };
我們有四種情況:
1. pack緊縮,complex _pack緊縮
2. pack緊縮,complex _pack默認(rèn)
3. pack默認(rèn),complex _pack緊縮
4. pack默認(rèn),complex _pack默認(rèn)
以下的排列均按此順序。
測(cè)試的結(jié)果
1:

2:

測(cè)試結(jié)果分析:
在兩個(gè)操作系統(tǒng)下,除了第一種情況----內(nèi)結(jié)構(gòu)體和外結(jié)構(gòu)體都緊縮----相同之外,其他三種情況都不相同。我們可以根據(jù)偏移畫(huà)出結(jié)構(gòu)體在內(nèi)存中的情況。第一種情況省略。
1:

2:

結(jié)論:#pragma pack只影響當(dāng)前結(jié)構(gòu)體的變量的對(duì)齊情況,并不會(huì)影響結(jié)構(gòu)體內(nèi)部的結(jié)構(gòu)體變量的排列情況。或者說(shuō)#pragma pack的作用域只是一層。我們由第三種情況,內(nèi)部結(jié)構(gòu)體正常,外部結(jié)構(gòu)體緊縮,可以得出結(jié)構(gòu)體的對(duì)齊是按偏移計(jì)算的。
這里還有一個(gè)問(wèn)題沒(méi)解決,為什么第二種情況內(nèi)部結(jié)構(gòu)體的偏移都是1?不是4或者8?