我最近在一个专门为任何struct
添加通用双链接队列的文件中偶然发现了一个使用地址操作技巧的宏:
#define queue_entry(ptr_link, type, listfield) \
((type *)((char *)(ptr_link)-(unsigned long)(&((type *)0)->listfield)))
这个宏的一个工作示例是:
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;
}
&((type *)0)->listfield
有效?由于空指针解除引用,我希望此时出现各种编译器错误。那究竟发生了什么?我在in the Linux kernel之前只见过类似的东西:
#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
,显然正在工作because of sizeof
being evaluated at compile time。在这里,没有这样的事情。unsigned long
和char *
?就像在,为什么使用两种不同的类型,这看起来与队列无关?