linux kernel源码中的container_of宏定义
linux kernel源码中有一个神奇的container_of宏,可以根据一个结构体中成员的地址计算出结构体自身的地址:
#define offset_of(type, member) ((size_t) &((type*)0)->member) /**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/ #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offset_of(type,member) );})
offset_of 的作用是求出结构体成员地址和结构体基地址之间的偏移,拿结构体成员的地址减去成员和结构体基地址之间的offset,就得到结构体的基地址了。
这个宏虽然神奇了一点,但仔细分析也不难理解。真正费解的是,为什么在container_of宏中定义了一个看起来毫无作用的临时变量__mptr,它仅仅把一个指针类型转换成指向常量的指针类型而已,完全可以这样定义container_of宏:
#define container_of(ptr, type, member) (type *)((char *)ptr - offset_of(type,member))
结果是完全一样的。
揣测一下这么写的可能原因:
1. linux kernel的开发者是认真严谨的程序员,定义__mptr是用来防止宏的副作用。container_of宏的第一个参数是指针变量,如果我们这样使用宏:container_of(p_member++, struct sample_struct, member_name),那么如果ptr在container_of宏中出现两次,那么ptr就自增了两次!多么危险的副作用!当然实际上container_of宏中ptr只出现了一次,但是认真严谨的程序员为了防止可能出现的可怕的副作用,习惯性的加上了这样一个常量。
2.linux kernel的开发者是认真严谨的程序员,定义__mptr是用来不小心对ptr指向内容的修改。虽然这个container_of宏里也没有对ptr所指的变量做任何修改,但是谁都不能确定宏里究竟会发生什么,认真严谨的程序员这样小心是完全有必要的。
3.linux kernel的开发者是高傲狭隘的程序员,定义__mptr是因为他们“可以定义__ptr”。typeof作为gcc的扩展特性之一,毫无疑问是灵活优越先进的;既然是先进的东西,用得着的时候要用,用不着的时候创造条件也要用。__mptr给了typeof一个绝好的露脸机会,所以无论如何是一定要定义的。

