许多C / C ++编译器(包括gcc和clang)都有一个名为packed结构的功能。它出于多种原因派上用场,但必须谨慎使用。一个潜在的缺陷是你使用指向结构成员的指针作为另一个函数的参数。现在该函数不知道未对齐的指针。让我用一些代码来说明我的意思:
#pragma pack(1)
typedef struct { int x; } uas;
#pragma pack()
void foo(int *f) {
// some code using the value of *f
}
void bar(uas *b) {
foo(&(b->x));
}
32位机器上int
的对齐通常为4.编译器现在可能生成foo()
的代码,如果f
不是4字节对齐,则可能无效。旧的ARM体系结构就属于这种情况。
现在struct uas
和其中的所有成员都具有1的对齐保证。显然,将b->x
的地址传递给foo()
是一个坏主意。
GCC和clang有一个编译器警告(-Wcast-align
),例如,通过将char*
强制转换为int*
来触发。使用指向打包结构成员的指针,即使两者都支持,也不会触发此警告。我还尝试了-Wall
和-Wextra
,但它们甚至没有包含-Wcast-align
。
我的主要问题是GCC,clang或任何其他支持打包结构的编译器是否有上述特定示例触发的警告。看来,如果编译器支持打包结构,这种警告是强制性的。
答案 0 :(得分:4)
clang刚刚针对此特定问题添加了新的-Waddress-of-packed-member
警告。有关详细信息,请参阅https://reviews.llvm.org/rL278483和https://llvm.org/bugs/show_bug.cgi?id=22821。它应该出现在clang的4.0版本中。
答案 1 :(得分:1)
gcc刚刚在gcc-9中添加了相同的警告(-Waddress-of-packed-member
)。使用-Wall
答案 2 :(得分:0)
考虑对 typedef 结构定义进行以下对齐:
#pragma pack(1)
typedef struct { int x; } uas __attribute__ ((aligned (sizeof(uint32_t))));
#pragma pack()
这将通知编译器确保结构的所有分配都对齐4个字节。
引用为here