Why this 0 in ((type*)0)->member in C?

2019-09-16 18:17发布

问题:

The container_of() macro in the Linux kernel is defined as:

#define container_of(ptr, type, member) ({ \
        const typeof( ((type*)0)->member) * __mptr =(ptr);\
        (type*)( (char*)__mptr - offsetof(type,member) );})

Why does this use ((type*)0)->member, not (type*)->member?

回答1:

Why this is ((type*)0)->member, not (type*)->member

Simply because (type*)->member would be invalid syntax, thus typeof would be impossible. So it uses a NULL pointer, which it doesn't dereference anyway - it's used just so typeof can refer to the member.


How this works:

  • The typeof trick is used to declare a pointer of the type of the member. This pointer gets is initialized with the pointer passed by the caller

  • The offset of that member in the struct is subtracted from the address of the pointer: this yields the address of the containing object


Subtler issue: why not get rid of typeof and just do ptr - offsetof. We're casting it to char * anyway, right ? In that case you could pass anything as ptr and the compiler won't say a thing. So the whole typeof things is there for (rudimentary) type checking.



回答2:

Because type* is a type and not a valid instance of the structure.

The pointer to zero is used to get a proper instance, but as typeof is resolved at compile-time and not at run-time the address used in the pointer doesn't have to be a proper or valid address.



标签: c kernel