簡體   English   中英

使用指針訪問未對齊的結構成員

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM