将container_of宏应用于嵌入式char数组时报告警告

时间:2016-10-10 15:04:18

标签: c gcc macros gcc-warning

当我将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似乎对类型检查有更严格的规则。

问:如何纠正此警告?

3 个答案:

答案 0 :(得分:1)

__mptr的声明无效,因为它只是在下一行中转换为char*。只需用以下代码替换宏:

#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))

注意: GCC 6.2.0未对原始代码发出任何警告,除非未使用的变量s

答案 1 :(得分:0)

数组类型本身不是constconst实际上来自每个成员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]中不兼容”。