当我将container_of
宏应用于包含char数组的C结构时,我得到警告:从不兼容的指针类型初始化。
以下是代码:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
struct st {
int a;
char b;
char c[16];
void *p;
};
int main(void)
{
struct st t = {
.a = 101,
.b = 'B',
.c = "hello",
.p = NULL
};
char (*p)[16] = &t.c;
struct st *s = container_of(p, struct st, c);
return 0;
}
似乎__mptr
的类型为[]
,由typeof()
推断。但是,ptr
本身就是(*)[]
类型。显然,它们不一样。
此外,如果我通过 clang 编译此代码,一切正常。 GCC似乎对类型检查有更严格的规则。
问:如何纠正此警告?答案 0 :(得分:1)
__mptr
的声明无效,因为它只是在下一行中转换为char*
。只需用以下代码替换宏:
#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
注意: GCC 6.2.0未对原始代码发出任何警告,除非未使用的变量s
。
答案 1 :(得分:0)
数组类型本身不是const
,const
实际上来自每个成员const
。实际上没有语法允许您声明数组本身是const
。您可以阅读this post了解更多详情。
然而,似乎GCC中的typeof
宏扩展存在缺陷,因为如果typeof
解析为数组类型,则const
限定符适用于数组而不是数组个人会员。 (André Sassi已注意到此问题似乎已在较新版本的GCC中得到解决。)
我不知道您认为可接受的解决方法是什么,但以下编译时没有发出警告。
const struct st *ct = &t;
typeof(ct->c) *p = &ct->c;
struct st *s = container_of(p, struct st, c);
答案 2 :(得分:0)
如果您知道传递给container_of
的成员是一个数组,您可以传递该数组的元素以避免警告:
char *p = &t.c[0]; /* or: char *p = t->c; */
struct st *s = container_of(p, struct st, c[0]);
避免警告的另一种方法是使指针成为void
:
void *p = &t.c;
struct st *s = container_of(p, struct st, c);
关于原始代码,似乎GCC的行为在GCC 4.9和GCC 5.4.1之间有所改变。更高版本的GCC不会为原始代码生成警告“不兼容的指针类型”。但是,使用更高版本的GCC启用-Wpedantic
会产生警告“指向具有不同限定符的数组的指针在ISO C [-Wpedantic]中不兼容”。