【发布时间】:2015-05-05 17:12:36
【问题描述】:
许多 C/C++ 编译器(包括 gcc 和 clang)都有一个称为打包结构的功能。由于多种原因,它派上用场,但必须谨慎使用。一个潜在的陷阱是您使用指向结构成员的指针作为另一个函数的参数。现在该函数不知道未对齐的指针。让我用一些代码来说明我的意思:
#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));
}
int 在 32 位机器上的对齐方式通常是 4。编译器现在可以为 foo() 生成代码,如果 f 不是 4 字节对齐的,则可能无法工作。旧 ARM 架构就是这种情况。
现在 struct uas 和其中的所有成员的对齐保证为 1。显然,将 b->x 的地址传递给 foo() 是个坏主意。
GCC 和 clang 有一个编译器警告 (-Wcast-align),例如,通过将 char* 转换为 int* 来触发该警告。即使两者都支持,使用指向压缩结构成员的指针似乎也不会触发此警告。我也试过-Wall和-Wextra,但它们甚至不包括-Wcast-align。
我的主要问题是 GCC、clang 或任何其他支持打包结构的编译器是否有一个由上面的特定示例触发的警告。看来,如果编译器支持打包结构,则这样的警告是强制性的。
【问题讨论】:
-
这非常接近this question,尽管更具体。不过,该答案中提到的The GCC bug report 专门讨论了指针。
-
好吧,如果你有这样一个打包的结构/类,你只传递目标中的起始地址和取消引用,这样可以避免传递未对齐变量的地址。如果开发者做了奇怪的事情,那么奇怪的事情就会发生。
-
有些人会犯错误。其他人不知道并且基本上接受他们机器上的任何工作都是“正确的”。这就是为什么我们有程序给我们“提示”人类可能做过坏事的原因。对这种特殊情况有一个“提示”真的很有意义。
-
您是否尝试在不允许非对齐访问整数的拱门上编译它?在 x86 上,现在不仅允许而且速度更慢(感谢缓存)。
-
我尝试为 ARM 进行交叉编译。我什至用clang尝试了-Weverything。
标签: c++ c pointers struct memory-alignment