static void device_release(struct device *dev)
{
struct device *rd = to_device(dev);
devm_kfree(dev, rd);
}
这段代码突然出现to_device函数,
搜索查看定义:grep -r -n "to_device"
#define to_device(obj) container_of(obj, struct device, dev)
container_of什么鬼?网上一搜吓一跳:内核第一宏。
好吧自己小白学习了记录下。
Linux 内核中的 container_of 宏
container_of 宏介绍
有了上面语句表达式和 typeof 的基础知识,接下来我们就可以分析 Linux 内核第一宏:container_of。这个宏在 Linux 内核中应用甚广。会不会用这个宏,看不看得懂这个宏,也逐渐成为考察一个内核驱动开发者 C 语言功底的不成文标准。废话少说,我们还是先一睹芳容吧。
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
作为内核第一宏,绝对不是盖的:看看这身段,这曲线,高端大气上档次,低调奢华有内涵,不出去再做个头发,简直就是暴殄天物。GNU C 高端扩展特性的综合运用,宏中有宏,不得不佩服内核开发者这天才般地设计。那这个宏到底是干什么的呢?它的主要作用就是:根据结构体某一成员的地址,获取这个结构体的首地址。根据宏定义,我们可以看到,这个宏有三个参数,它们分别是:
- type:结构体类型
- member:结构体内的成员
- ptr:结构体内成员member的地址
也就是说,我们知道了一个结构体的类型,结构体内某一成员的地址,就可以直接获得到这个结构体的首地址。container_of 宏返回的就是这个结构体的首地址。
container_of 宏使用示例
比如现在,我们定义一个结构体类型 student:
struct student
{
int age;
int num;
int math;
};
int main(void)
{
struct student stu;
struct student *p;
p = container_of( &stu.num, struct student, num);
return 0;
}
在这个程序中,我们定义一个结构体类型 student,然后定义一个结构体变量 stu,我们现在已经知道了结构体成员变量 stu.num 的地址,那我们就可以通过 container_of 宏来获取结构体变量 stu 的首地址。
这个宏在内核中非常重要。我们知道,Linux 内核驱动中,为了抽象,对数据结构体进行了多次封装,往往一个结构体里面嵌套多层结构体。也就是说,内核驱动中不同层次的子系统或模块,使用的是不同封装程度的结构体,这也是 C 语言的面向对象思想。分层、抽象、封装,可以让我们的程序兼容性更好,适配更多的设备,但同时也增