前不久,在C++程序中碰到一個有關結構體字節對齊的問題。c++
一。問題描述數組
在程序中,定義了一個結構體,以下:
typedef struct
{
char name[33];
int ID;
int age;
} PERSON;網絡
聲明瞭一個該結構體的數組:
PERSON peo[30];佈局
當從結構體中取出ID字段給一個int類型的局部變量賦值時,卻出現異常.
好比結構體中的字段都已經有初始值
peo[0].ID =4;調試
下面的賦值語句
int tempID = peo[0].ID;
卻不能正確獲得數值4,tempID獲得的是67108864.
經檢查67108864是4在高位時的數值大小.
賦值時原本應該是取內存中的四個Bytes:"04 00 00 00"
但是取值時倒是用"00 00 00 04" 的方式.
在調試過程當中,從peo[0].ID取值是正確的,獲得數字4,可程序執行上面賦值語句後:
tempID仍是獲得的是67108864.內存
也就是說,在調試器中取值是正確的,彙編後的程序取值倒是不正確的.
程序在開始用了的很長一段時間並無出現這種問題,這個問題是最近才發生的.
真是百思不得其解。還有一點是明確的,程序涉及到網絡傳輸。編譯器
但是若是把結構體中的字符數組大小由33改成36,一切正常了!編譯
原理上確定是結構體的位對齊問題,但爲何之前編譯使用沒出問題,如今編譯才發生呢?
應該怎麼解決呢?社區
二。尋找問題的緣由。變量
通過CSDN社區各位老大的幫助,而且本身仔細去了解程序中的編譯條件部分,原則上理解了這問題的本質所在。
發如今網絡模塊中使用到了"#pram pack(1)"這樣的編譯條件,而其它模塊則沒有加入這種編譯條件。
而CSDN中其中一個大蝦是這樣解釋的:「對齊方式是給編譯器看的,編譯器根據這個來決定內存佈局。一旦編譯成二進制文件內存佈局就已經肯定了,若是兩段代碼對同一個結構使用的對齊方式不一樣,那麼就會對內存裏的值作出了不一樣的解釋,賦值的一方認爲char[33]佔了36個字節,從第37個字節填寫04 00 00 00,但是讀取的一方認爲char[33]只有33個字節,那就從第34個字節處取四個字節看成ID。」
此次網友的解釋,我認爲指出了問題的本質所在:「若是兩段代碼對同一個結構使用的對齊方式不一樣,那麼就會對內存裏的值作出了不一樣的解釋」。咱們的程序給結構體初始化部分是按VC編譯器中默認的結構體8字節對齊,而在網絡模塊中,因爲使用了"#pram pack(1)",結果從結構體中取值時,編譯器認爲結構體是按1字節對齊,最終致使了問題的產生。
三。解決方法
爲了解決這個問題,就須要程序中全部的代碼對同一個結構體都使用同一種對齊便可。
會有兩種解決辦法:
一是把網絡模塊中的"#pram pack(1)"去掉,結構體都是按VC編譯器中默認的結構體8字節方式對齊。
二是設置結構體按1字節方式進行對齊,程序全部模塊都按這種對齊方式編譯。
設置在VC的"project"->"setting..."->"c/c++":struct member aligment改爲1 Bytes.