http://blog.csdn.net/lqk1985/archive/2008/10/23/3129976.aspx
對(duì)于讀取數(shù)據(jù)流時(shí)(如網(wǎng)絡(luò)或文件)要特別注意。
比如
PBYTE pData;
//指向接收到的數(shù)據(jù)流
int * pi = pData + 這次接收到數(shù)據(jù)流的大小 - 4;
//指向接收到數(shù)據(jù)流的最后4位,可能客戶端發(fā)過(guò)來(lái)的這個(gè)數(shù)據(jù)流最后4位是int,那樣就是對(duì)齊好的了。也有可能不是int。
if *pi = 4561321 endparse data;//判斷作為數(shù)據(jù)流的結(jié)束標(biāo)志,最后4位的前面可能是全是char的。
由于這最后4位可能不是int,那樣就有可能不對(duì)齊,這里就會(huì)出現(xiàn)Datatype misalignment錯(cuò)誤。但是我們還是必須通過(guò)最后4位作為結(jié)束標(biāo)志,而只有知道什么時(shí)候結(jié)束才能用int指針指向最后4位才不會(huì)出現(xiàn)對(duì)齊錯(cuò)誤。這樣形成了一個(gè)死循環(huán),難道沒(méi)辦法解決了么?
PBYTE pData;
PBYTE * pi = pData + 這次接收到數(shù)據(jù)流的大小 - 4;
int i;
memcpy(&i, pi, 4);
if i = 4561321 endparse data;
這樣就可以解決用int* pi指向未對(duì)齊的int錯(cuò)誤了。
這一招對(duì)所有碰到Datatype misalignment的數(shù)據(jù)的訪問(wèn)應(yīng)該都有效,就是把Datatype misalignment的數(shù)據(jù)用memcpy拷貝到對(duì)齊的內(nèi)存來(lái)訪問(wèn)。
1,解析數(shù)據(jù)流時(shí)應(yīng)該時(shí)刻注意。如果需要把一個(gè)數(shù)據(jù)流(BUFFER)轉(zhuǎn)化成結(jié)構(gòu)進(jìn)行取值,就應(yīng)該把這個(gè)結(jié)構(gòu)定義為按字節(jié)存取.考慮如下結(jié)構(gòu):
struct a{
char a;
short b;
long c;
};
如果某個(gè)數(shù)據(jù)流中包含這樣的結(jié)構(gòu),而且我們要直接將數(shù)據(jù)流的指針轉(zhuǎn)化成該結(jié)構(gòu)的指針,然后直接取結(jié)構(gòu)成員的值,我們就應(yīng)該將這個(gè)結(jié)構(gòu)定義成按字節(jié)訪問(wèn),即將其夾在語(yǔ)句
#pragma pack(push,1)//設(shè)為1字節(jié)對(duì)齊
...
#pragma pack(pop)//還原為原來(lái)的字節(jié)對(duì)齊方式
之中。如果我們不這樣做,編譯器會(huì)將成員b的地址對(duì)齊到short指針的地址,即在a之后加上一個(gè)char即8位的成員,將C對(duì)齊到LONG,即在B之后再加一個(gè)char成員。如此一來(lái),成員B和成員C就得不到正確的值了。
pragma pack 只作用于結(jié)構(gòu)的定義,而不是分配內(nèi)存空間。把一個(gè)結(jié)構(gòu)定義為pack1后,這個(gè)結(jié)構(gòu)在程序中就一直是1了。
上面這個(gè)例子是客戶端發(fā)送3個(gè)連續(xù)的數(shù)據(jù)不是發(fā)送結(jié)構(gòu)體,服務(wù)端接收結(jié)構(gòu)體。
如果客戶端也發(fā)送結(jié)構(gòu)體,服務(wù)端也接收結(jié)構(gòu)體就不需要這樣了。但是前提是雙方的對(duì)齊方式一致。所以在客戶端發(fā)送前也要用#pragma pack()一下,服務(wù)端也要#pragma pack()一下。
最好還是客戶端也單個(gè)數(shù)據(jù)發(fā)送,服務(wù)端也單個(gè)數(shù)據(jù)接收。
如果我們定義一個(gè)普通的結(jié)構(gòu)用來(lái)存放一些數(shù)據(jù),則不用定義成按字節(jié)存取,編譯器會(huì)加上一些占位成員,但并不會(huì)影響程序的運(yùn)行。從這個(gè)意義上講,在ARM中,將結(jié)構(gòu)成員定義成CHAR和SHORT來(lái)節(jié)約內(nèi)存是沒(méi)有意義的。
一個(gè)典型的例子就文件系統(tǒng)的驅(qū)動(dòng)程序,文件是以一些已經(jīng)定義好的結(jié)構(gòu)存放在存儲(chǔ)介質(zhì)上的,它們被讀取到一個(gè)BUFFER中,而具體取某個(gè)文件、目錄結(jié)構(gòu)時(shí),我們會(huì)將地址轉(zhuǎn)化成結(jié)構(gòu)而讀取其中的值。
2,訪問(wèn)外設(shè)時(shí)。
例如,磁盤驅(qū)動(dòng)通常以16BIT的方式存取數(shù)據(jù),即每次存取兩個(gè)字節(jié),這樣就要求傳給它的BUFFER是雙字節(jié)對(duì)齊的,驅(qū)動(dòng)程序應(yīng)該至上層傳來(lái)的指針做出正確的處理以保證數(shù)據(jù)的正確性。
3.有時(shí),我們沒(méi)有將數(shù)據(jù)流指針轉(zhuǎn)化為結(jié)構(gòu)指針取值,但如果我們讀取的是雙字節(jié)或者是四字節(jié)的數(shù)據(jù),同樣需要注意對(duì)齊的問(wèn)題,例如,如果從一個(gè)BUFFER的偏移10處讀取一個(gè)四字節(jié)值,則實(shí)際得到的值是偏移8處的
地址上的DWORD值。
本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/lqk1985/archive/2008/10/23/3129842.aspx