【发布时间】:2020-01-16 02:31:09
【问题描述】:
我一直在研究现有的 C99 代码库,该代码库在各处使用指向压缩结构成员的指针。这会导致表单出现警告。
my_file.c:xxx:yy: error: taking address of packed member of 'struct some_packed_struct' may result in an unaligned pointer value [-Werror=address-of-packed-member]
大多数时候,这些警告是在将指向结构成员的指针传递给函数时生成的。例如:
int bar(const int *val)
{ ... }
struct {
int a;
char b;
int c;
} __attribute__((packed)) foo;
// &foo.c is not aligned
bar(&foo.c)
这个问题有很多不同的解决方案。立即想到的一个是将memcpy() 的值传递给相同类型的堆栈分配变量,并将指针传递给该堆栈变量。
int tmp;
memcpy(&tmp, &foo.c, sizeof(foo.c));
bar(&tmp)
虽然这行得通,但会产生很多我宁愿避免引入的样板代码。
目前,我一直在考虑使用表单的宏
#define ALIGN_VALUE_PTR(val) (&((const typeof(val)) { val }))
bar(ALIGN_VALUE_PTR(foo.c));
这适用于标量类型。但是,可以预见的是,如果 val 是 struct,这将不起作用。
struct inner {
int c, d;
};
struct outer {
int a, b;
struct inner inner;
};
void print_inner_field(const struct inner *inner)
{
printf("value is %d\n", inner->c);
}
struct outer outer;
print_inner_field(ALIGN_VALUE_PTR(outer.inner));
lol.c:28:30: error: incompatible types when initializing type ‘int’ using type ‘struct inner’
28 | print_inner(ALIGN_VALUE_PTR(foo.inner));
| ^~~
lol.c:3:55: note: in definition of macro ‘ALIGN_VALUE_PTR’
3 | #define ALIGN_VALUE_PTR(val) (&((const typeof(val)) { val }))
| ^~~
我想知道是否有人比我的想法更好。
【问题讨论】:
-
如果你刚刚删除了
__attribute__((packed))会发生什么? -
一个更好的主意是放弃传递指针和传递值的约定,因为如果这样有效,那么通过引用传递是没有意义的。
-
我认为这里也存在一些 XY 问题,但是“如何制作结构的复合文字临时副本”的问题在打包结构(它们是邪恶)。
-
使用你的 '
memcpy到tmp' 变体,你通过引用函数来传递变量,所以可能函数可能会修改它,因此你也应该memcpy从tmp回到未对齐的结构。或者你应该问自己“为什么函数传递一个指针?” (即使它是指向 const 数据的指针)。 -
@JonathanLeffler:是的,这也是我的想法,但只要代码是 const 正确的,
const有助于避免问题。
标签: c c-preprocessor c99