分类: LINUX
2008-07-27 13:10:42
file_operation 结构中的open函数定义如下:
int (*open)(struct inode *inode, struct file* filp);
inode中含有i_cdev属性,它描述的是字符设备。在自己定义的字符设备中,一般会包含字符设备的指针,而open方法被调用时,通常需要获取特定的设备对象,这里就涉及到一个问题:如何通过结构中的某个变量获取结构本身的指针。Linux内核中提供了container_of宏(WDM中也定义了相似功能的宏)。C99中定义了两个宏,typeof和offsetof,它们返回的是某个变量的类型和结构中某变量在结构中的偏移量。可以预想的是,没有编译器的支持,container_of的宏是很难实现的(至少我还没有想出能够不用typeof宏实现container_of的方法)。
下面是container_of宏的标准实现:
container_of宏定义在[include/linux/kernel.h]中:
#define container_of(ptr, type, member) \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );
offsetof宏定义在[include/linux/stddef.h]中:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
值得一提的是,offsetof宏的实现非常巧妙,它把0地址转化为TYPE结构的指针,然后获取该结构中MEMBER成员的指针,并将其强制类型转换为size_t类型。于是,由于结构从0地址开始定义,因此,cast后的MEMBER成员地址,实际上就是它在结构中的偏移量。这也显示出了C语言中指针的强大。因为,在某个体系结构下实现的libc,结构中各个成员的偏移总是可以预见的,这比C#那种以托管的方式管理内存的自由度要大的多。