Report warning when apply container_of macro to embedded char array

假如想象 提交于 2021-02-08 05:39:38

问题


When I apply container_of macro to a C struct which contains an array of char, I got warning: initialization from incompatible pointer type.

Here is the codes:

#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;
}

It seems that the type of __mptr is [], which is deduced by typeof(). However, ptr itself is type (*)[]. Obviously, they are not the same.

Besides, if I compile this code by clang, everything is OK. GCC seems have a more strict rule for type checking.

Q: How to correct this warning?


回答1:


The declartion of __mptr is unuseful, since it is simply cast to char* in the next line. Just replace the macro with:

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

Note: GCC 6.2.0 didn't give any warning for the original code, unless for the unused variable s.




回答2:


An array type is itself not const, the constness is actually from each individual member being const. There is actually no syntax allowing you to declare that an array itself is const. You can read this post for additional details.

It seems, however, that the typeof macro extension in GCC is flawed in that if typeof resolves to an array type, the const qualifier applies to the array rather than to its individual members. (André Sassi has noted this issue seems to have been resolved in a newer version of GCC.)

I don't know what you would consider an acceptable workaround, but the following compiles without the noted warning.

const struct st *ct = &t;
typeof(ct->c) *p = &ct->c;
struct st *s = container_of(p, struct st, c);



回答3:


If you know the member being passed to container_of is an array, you can pass an element of that array instead to avoid the warning:

char *p = &t.c[0]; /* or: char *p = t->c; */
struct st *s = container_of(p, struct st, c[0]);

Another way to avoid the warning is to make the pointer a pointer to void:

void *p = &t.c;
struct st *s = container_of(p, struct st, c);

Regarding the original code, it seems the behaviour of GCC changed sometime between GCC 4.9 and GCC 5.4.1. The later version of GCC doesn't produce the warning "incompatible pointer type" for the original code. However, enabling -Wpedantic with the later version of GCC produces the warning "pointers to arrays with different qualifiers are incompatible in ISO C [-Wpedantic]".



来源:https://stackoverflow.com/questions/39961293/report-warning-when-apply-container-of-macro-to-embedded-char-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!