Linux内核中的宏/container_of分析

嵌入式技术

1367人已加入

描述

今天在看平台设备实现的时候,看到to_xxx开头的“函数”。包括在内核中也有很多此类的“函数”,其实他们都是container_of的宏。因为内核是链表和结构体的世界,因此内核中有大量需求要 根据结构体成员获取结构体地址 ,或者根据结构体类型和结构体成员类型获取成员在结构体的偏移

内核

match函数

内核

最后container_of的实现如下:内核

根据注释可以得到几点信息:container_of的作用是根据结构体成员地址找结构体地址

ptr是指向成员的指针

type是结构体的类型

member是成员的名字

下面来分析一下这到底如何实现。

const typeof( ((type *)0)->member ) *__mptr = (ptr);

这句话实际上仅仅是把ptr的地址传给一个临时的变量__mptr。const表明__mptr不会修改ptr指向的数据,具体就是结构体成员的数据。typeof是扩展关键字,用于获取某个变量的类型,确保menber的类型和传入的ptr指向的数据类型一致。

接下来的重点就是:

((type *)0)->member如何理解?

先来概括一下:用一个指向0地址的指针,获取结构体的成员变量。

看看平时是如何获取一个结构体变量的,首先初始化一个结构体实例a,然后声明一个结构体指针指向这个实例:struct xxx *p = &a;此时 p = a的地址,等价于 (struct xxx *)&a;

再看看(type *)0是不是很像?type就是结构体的类型,0就是某个结构体实例的地址。就是把结构体实例放到0地址嘛!((type *)0)等价于一个指针,这个指针指向0地址,类型是type类型。接下来都水到渠成。

总结一下:const typeof( ((type *)0)->member ) *__mptr = (ptr);仅仅是把传入的ptr地址赋给_mptr临时变量,得到的_mptr是一个绝对地址。假设是20,后面会用到。

(type *)( (char *)__mptr - offsetof(type,member) );})

先看offsetof(type,member) )的实现

内核

offsetof

这里和上面分析的一样,只不过多了一个取地址符号:把结构体实例放到0地址,然后获取成员变量,然后取地址,这时候取出的地址是相对0偏移的地址,也是相对于结构体地址的偏移地址,假设是4.

那么__mptr - offsetof = 20 - 4 = 16 = 结构体地址(绝对地址)。

理解了这个,其他都是一些类型检查,边角料。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分