2

Recently, I saw something cool.

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

Basically, I know what this macro does. But there is one thing I can't understand.

Why can we cast 0 into pointer type ( struct ) and access its member ? I have already referenced some similar stuff and 0 seems like a null pointer. So why can we cast a null pointer and then access its member?

dbush
  • 205,898
  • 23
  • 218
  • 273
Steven
  • 811
  • 4
  • 23
  • 3
    I'll leave the full answer to the language lawyers, but the short answer is: We don't access its member. We only take the `typeof` that member. This is a compile-time operation that doesn't do any pointer dereferencing at runtime. – Thomas Feb 03 '20 at 13:19
  • 3
    The term you are looking for is *unevaluated context*. – 0x5453 Feb 03 '20 at 13:20
  • 1
    This link has a good explanation https://radek.io/2012/11/10/magical-container_of-macro/ – Karthick Feb 03 '20 at 13:24
  • 3
    BTW, the nonstandard parts of the macro, which facilitate a type check, aren't even needed. The typecheck can be done perfectly within the bounds of the standard: `((type *)( (char *)(0? &(type){0}.member : (ptr)) - offsetof(type,member) ))` – Petr Skocik Feb 03 '20 at 13:34

2 Answers2

3

typeof is a gcc extension. The result of this operator is a type name.

This works because its operand is evaluated at compile time, so a pointer need not actually point to anything. The documentation for this operator states:

The operand of typeof is evaluated for its side effects if and only if it is an expression of variably modified type or the name of such a type.

Since a struct can't contain a variable length array, this guarantees typeof( ((type *)0)->member ) will not be evaluated at run time, so this is a safe operation.

dbush
  • 205,898
  • 23
  • 218
  • 273
0

In the code sample you list, it is casting 0 within typeof. But typeof is not a function, it is an operator. You are accessing the type of it and not the value of it.

Reference this question: Why is typeof null "object"?

Dan Eisenhut
  • 141
  • 1
  • 2
  • 8