I have recently stumbled upon this macro using address a manipulation trick, in a file dedicated to adding generic doubly linked queues to any struct
:
#define queue_entry(ptr_link, type, listfield) \
((type *)((char *)(ptr_link)-(unsigned long)(&((type *)0)->listfield)))
A working example of this macro would be :
struct link {
struct link* next;
struct link* prev;
};
struct mystruct {
//...
struct link chaining;
//...
}
int main() {
struct link ex_link;
struct mystruct *ex_struct = malloc(...);
ex_struct->chaining = ex_link;
queue_entry(&ex_link, struct mystruct, chaining); // returns ex_struct
return 0;
}
- Why is
&((type *)0)->listfield
working? I would expect all kinds of compiler errors at this point, due to a null pointer dereferencing. So what happens exactly? I have only seen something similar once before in the Linux kernel:#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
, which was apparently working because ofsizeof
being evaluated at compile time. Here, there is no such thing. - Why the respective casts to
unsigned long
andchar *
? As in, why use two different types, and that are seemingly unrelated to the queue?