[英]Accessing unaligned struct member using pointers
我有以下結構:
typedef struct __attribute__ ((__packed__))
{
uint16_t a;
uint32_t b;
} st_t;
-> "b" 成員未對齊。
當我執行以下操作時,gcc 會發出警告:
st_t st;
uint32_t * b_p = &st.b;
*b_p = 0;
警告日志:
taking address of packed member of 'struct <anonymous>' may result in an unaligned pointer value
但是當我執行以下操作時,它不會發出任何警告:
st_t st;
st_t * st_p = &st;
st_p->b = 0;
我不明白為什么它不會在第二種情況下發出警告,因為我仍在訪問一個未結盟的成員。
無法提供標准報價,因此其他人肯定會寫出更好的答案,但這里有一個簡短的。
對於打包結構,從“打包結構”的定義來看,編譯器必須為任何成員訪問生成工作機器代碼。 未對齊的訪問是已知的,並將針對 CPU 進行適當的處理。
然而,指向 int 的指針被假定指向一個有效的 int,這可能意味着它必須對齊(或者會有“總線錯誤”或類似的情況)。 編譯器為每個 int 指針取消引用生成有效的未對齊訪問機器代碼在重要的 CPU 上效率很低,因此編譯器基本上必須做出這個假設。
因此,如果編譯器注意到一個指向未對齊地址的指針,它會正確地發出警告,因為它在某些 CPU 上是非法操作,即使它是合法的,它也可能比對齊訪問慢。 它不會對打包結構發出警告,因為程序員通過使結構打包來明確地說“這是未對齊的,處理它”。
這是來自 GCC 的設計不當的警告。
當您將packed
屬性應用於結構時,它會使其成員的 alignment 要求為一個字節。 因此,當您獲取uint32_t
成員的地址時,您得到的不是uint32_t *
而是uint32_t __attribute__ ((__aligned__(1))) *
。 1將此地址分配給uint32_t __attribute__ ((__aligned__(1))) *
或(使用強制轉換)分配給unsigned char *
是有效的。
因此,理想情況下,當您獲取成員的地址時,編譯器不會警告您,而是當您以需要比保證更大的 alignment 的方式使用它時。 在創建對打包結構的支持並添加此警告時,實施此類警告可能很困難。
在這段代碼中:
st_t st;
st_t * st_p = &st;
st_p->b = 0;
st_t
的地址被占用並分配給st_t *
,所以沒有問題。 然后st_p->b
訪問成員b
但不獲取其地址,因此不存在未對齊地址可能用作指向對齊地址的指針的危險,因此不需要警告。
1 GCC 的aligned
屬性只允許增加一個類型的 alignment 要求,而不是減少它。 packed
可以減少 alignment 要求,但 GCC 在普通uint32_t
上不接受它。 因此,在此答案中使用__aligned__(1)
表示法來傳達具有單字節 alignment 要求的uint32_t
的意圖,盡管事實上似乎無法在 GCC 中指定這一點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.