问题
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 const
ness 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