宏 return 怎么可能是指向未对齐值的对齐指针?
How could a macro return an aligned pointer to an unaligned value?
我一直在研究现有的 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 }))
| ^~~
我想知道是否有人有比我想出的更好的主意。
#define ALIGN_VALUE_PTR(val) (((const typeof(val) []) { val }))
您的原始版本不起作用的原因是因为初始化器中大括号的处理方式很微妙,而且复合文字总是需要至少一级大括号。您可以将结构初始化为
struct s bar;
//...
struct s foo = bar;
但你做不到:
struct s foo = { bar };
因为在大括号内,bar
的类型必须与 struct s
的第一个成员相匹配,而不是 struct s
.
使用数组(或结构;也有涉及无偿结构的变体)允许您匹配大括号级别以使用您想要的结构类型作为初始值设定项。数组形式当然以数组类型开始,并且仅通过衰减成为指针。如果你想确保它总是一个指针,添加一个无偿的 +0
或 &*
来强制衰减。
我一直在研究现有的 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 }))
| ^~~
我想知道是否有人有比我想出的更好的主意。
#define ALIGN_VALUE_PTR(val) (((const typeof(val) []) { val }))
您的原始版本不起作用的原因是因为初始化器中大括号的处理方式很微妙,而且复合文字总是需要至少一级大括号。您可以将结构初始化为
struct s bar;
//...
struct s foo = bar;
但你做不到:
struct s foo = { bar };
因为在大括号内,bar
的类型必须与 struct s
的第一个成员相匹配,而不是 struct s
.
使用数组(或结构;也有涉及无偿结构的变体)允许您匹配大括号级别以使用您想要的结构类型作为初始值设定项。数组形式当然以数组类型开始,并且仅通过衰减成为指针。如果你想确保它总是一个指针,添加一个无偿的 +0
或 &*
来强制衰减。