看LDD3时,碰到了这个Macro。还是有点意思的,在<linux/kernel.h>中定义如下:
/**
* 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 - offsetof(type,member) );})
1.
困扰的是这个
(type *)0)的使用。C语言可以把一个地址转换成任意一种数据类型的,0也是一个地址,可能有人会想说转换地址0不会有问题吗,好问题,答案是,地址0在这里只是被转换,而没有被访问,如果访问地址0,那肯定是会segment fault,那这里并不会访问地址0,所以不会有问题
2. typeof:这是GCC对C语言做的扩展,用于获得一个变量的类型,详细可戳
这里
3. offsetof也是宏,定义在<
linux/stddef.h>,如下:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
在这里,TYPE表示一个结构体的类型,MEMBER是结构体中的一个成员变量的名字。offsetof 宏的作用是计算成员变量 MEMBER 相对于结构体起始位置的内存偏移量,以字节(Byte)为单位。
它的计算原理是,把整数0进行强制类型转换,转换为一个 TYPE 类型的指针; 然后找到成员变量 MEMBER; 最后用取地址符 & 得到 MEMBER 的地址。 因为结构体是从地址0处开始的,所以 MEMBER 的地址就是其相对于结构体起始位置的偏移量。
它的计算原理是,把整数0进行强制类型转换,转换为一个 TYPE 类型的指针; 然后找到成员变量 MEMBER; 最后用取地址符 & 得到 MEMBER 的地址。 因为结构体是从地址0处开始的,所以 MEMBER 的地址就是其相对于结构体起始位置的偏移量。