在内核代码中,经常见到container_of函数,它是一个宏定义,定义在include\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 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)放到指定结构体(type)中,并返回直接结构体的指针(type)。内存存储示意图如下:
这个宏定义是怎么做到的呢?首先看第一句
Const typeof(((type *)0)->member) *__mptr = (ptr);
这里是定义一个指针变量__mptr,并赋值为ptr.
Typeof关键字的作用是返回变量或者表达式的数据类型,所以__mptr的指针类型和((type *)0)->member的指针类型一致;这句话的作用是为了保证ptr的类型与member的数据类型一致,当两者不一致时,编译器则会发出警告信息提醒开发者。
接下来看第二句
(type *)((char *)__mptr – offsetof(type,member));
这里是使用__mprt指针地址减去member成员在type结构体的偏移,即可得到想要的type结构体的指针,这个指针内存包含着ptr。
offsetof(type,member)表示member成员在type结构体的位置偏移,offsetof的定义如下:
#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
这里的&是取地址符号,取MEMBER相对于TYPE的地址,因为这里的开始地址是0,所以取出来的地址就是MEMBER在TYPE结构体中的偏移量。
至此,我们已经知道了container_of的作用和怎么实现的了,但是,我有一个疑惑,使用它是否存在篡改其它指针的内容的可能性,因为我们直接对指针做减法得到新的指针后直接使用,假如新的指针原先已经分配给别的变量,且该变量还在被使用,我认为就会存在被篡改的可能性。那内核是使用什么机制避免这样的事情发生的呢?