详解container_of

    container_of宏在linux中的应用非常广泛,几乎随处可见,它的作用是通过一个结构体成员的地址来获得这个结构体的首地址。先来看一下定义:

#undef offsetof
#define offsetof(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 - offsetof(type,member) );})

三个成员的含义:

ptr:结构体成员的地址

type:结构体类型

member:结构体成员的名字

举例说明用法,比如有如下结构体:

struct data{
	int i;
	int j;
	char c;
};
struct data value;

现在已知value.j的首地址,想获得value的首地址,可以使用container_of(&value.j, struct data, j);

下面来分析一下实现过程:

1、typeof是GNU C的扩展,作用是根据变量来获取变量的类型,对本例来说,就是获取了j的类型int,然后定义一个int型指针__mptr,并把j的地址赋给__mptr。

2、第二句中offsetof用来求某个结构体成员在结构体中的偏移值,在本例中,即j相对与结构体value的偏移,先把0地址转换为一个指向value的结构体类型的指针,然后取出其j成员的地址,因为这个地址是相对于0地址的,所以本身值就代表成员的偏移量,size_t是对地址进行的强转。

3、用j的地址减去j在结构体中的偏移,得到的即为结构体的首地址。


关于0指针

0指针在这里是不会崩溃的,因为这个表达式本身并不会被求值。编译器在乎的指示它的类型。编译器并不关心0指针的值,编译器会在分配给结构体的地址加上该成员的偏移,并且返回加上偏移之后的新地址。

你可能感兴趣的:(Linux,kernel)