我們知道,c編譯器在編譯32位機目標**時,預設將變數儲存的位址按照4位元組進行對齊。
在使用結構體時,由於位元組對齊的原因可能會造成儲存空間的浪費
例如:struct aaaa
結果,sizeof(aa)=12
。成員a與b之間空出了3個空位元組,成員c也後也空出了3個位元組。
這個時候雖然記憶體空間有些浪費
,但是並不會誤導程式設計師進行編碼
。如果和聯合體一起使用
,就可能會造成一定的誤解。
例如:struct aa;
int data;
}}aa
此處本來想將 byte0 -byte3作為 data的4個位元組的重名以便對data的其中任意8bit進行操作。但是由於四位元組對齊的原因只有byte0是data的第0位元組,byte1-byte3每乙個成員都向後偏移了四個位元組。
為了達到預期的效果,可以使用#pragma pack(n) 對編譯器進行位元組對齊設定。
#pragma pack(1)//按照1位元組進行對齊
struct aa;
int data; }
}aa#pragma pack()//取消對齊設定
這樣就可以達到預想的效果,使用byte0-byte3對data的每個位元組進行單獨的操作。
但是今天,由於我在使用#pragma pack() 指令犯了錯誤,產生了結構體成員賦值失敗的情況。
情況如下:
檔案a
struct aaaa
檔案b#pragma pack(1)//按照1位元組進行對齊
struct _cc;
int data; }
}ccaa.b = 0x02;//此處給成員b賦值失敗
#pragma pack()//取消對齊設定
我在檔案a中使用預設的對齊設定(4位元組對齊),建立了結構體aa。然後aa作為全域性變數在檔案b中進行賦值。
但檔案b由於cc結構體的需要設定了1位元組對齊
對結構體aa成員的賦值語句放在了取消對齊設定之前,編譯器在編譯檔案b時對變數aa.b按照1位元組對齊進行了操作,所以成員b的偏移位址為1。而實際上在定義aa時,成員b的偏移位址為4(a與b之間插入了3個空位元組)
所以賦值並沒有成功,而是將0x02寫入了aa.a 與aa.b中間的填充位元組。
在**這段程式時,就出現了賦值不成功的奇怪現象。
那麼應該如何解決這個問題呢?
那就是謹慎的使用#pragma pack(n)指令
將需要對齊的結構體宣告放在#pragma pack(n) 與 #pragma pack()之間,其他的**不要放在這裡面,特別是對對齊設定不同的結構體進行訪問的**段。
檔案b改為
#pragma pack(1)//按照1位元組進行對齊
struct _cc;
int data; }
}cc#pragma pack()//取消對齊設定
aa.b = 0x02;//此處給成員b賦值成功
結構體位元組對齊
include pragma pack 2 struct t.pragma pack int main int argc,char argv 最後輸出的結果為 8。這個表示是按照2位元組來對齊資料,首先分配2位元組給成員變數i,分配完成後,還剩一位元組,zj add補0 沒法容納成員變數d,此時會再...
結構體位元組對齊
include pragma pack 2 struct t.pragma pack int main int argc,char argv 最後輸出的結果為 8。這個表示是按照2位元組來對齊資料,首先分配2位元組給成員變數i,分配完成後,還剩一位元組,zj add補0 沒法容納成員變數d,此時會再...
結構體位元組對齊
在用sizeof運算子求算某結構體所佔空間時,並不是簡單地將結構體中所有元素各自佔的空間相加,這裡涉及到記憶體位元組對齊的問題。從理論上講,對於任何 變數的訪問都可以從任何位址開始訪問,但是事實上不是如此,實際上訪問特定型別的變數只能在特定的位址訪問,這就需要各個變數在空間上按一定的規則排列,而不是...