list_entry()详解
来源:互联网 发布:每日推荐软件 编辑:程序博客网 时间:2024/04/24 22:27
转载地址:http://blog.csdn.net/hs794502825/article/details/10364977
#define list_entry(ptr, type, member) /
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
这个倒是不难理解:从一个结构的成员指针找到其容器的指针。
container_of(ptr, type, member)
#define container_of(ptr, type, member) /
({ /
const typeof( ((type *)0)->member ) *__mptr = (ptr);/
(type *)( (char *)__mptr - offsetof(type,member) ); /
})
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
ptr是指向list_head类型链表的指针,type为一个结构,而member为结构type中的一个域,类型为list_head,这个宏返回指向type结构的指针。在内核代码中大量引用了这个宏,因此,搞清楚这个宏的含义和用法非常重要。
设有如下结构体定义:
typedef struct xxx
{
……(结构体中其他域,令其总大小为size1)
type1 member;
……(结构体中其他域)
}type;
定义变量:
type a;
type * b;
type1 * ptr;
执行:
ptr=&(a.member);
b=list_entry(ptr,type,member);
则可使b指向a,得到了a的地址。
如何做到的呢?
先看&((type *)0)->member:
把“0”强制转化为指针类型,则该指针一定指向“0”(数据段基址)。因为指针是“type *”型的,所以可取到以“0”为基地址的一个type型变量member域的地址。那么这个地址也就等于member域到结构体基地址的偏移字节数。
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
Linux内核中,获取节点地址的函数list_entry()非常常用,由于其定义有点晦涩,先解析如下:
list_entry的宏定义:
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
这个倒是不难理解:从一个结构的成员指针找到其容器的指针。
但是正因为如此,我的第一感觉是,这个宏的名字应该更加抽象,名字似乎应该改称叫“寻找容器”一类的,查看list.h源代码,发现现在的定义是这样的:
#define list_entry(ptr, type, member) /container_of(ptr, type, member)
#define container_of(ptr, type, member) /
({ /
const typeof( ((type *)0)->member ) *__mptr = (ptr);/
(type *)( (char *)__mptr - offsetof(type,member) ); /
})
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
linux不想用C++,但又想利用C++的优点,如是出现了很多奇怪的宏,他们叫做trick。
ptr是找容器的那个变量的指针,把它减去自己在容器中的偏移量的值就应该 得到容器的指针。(容器就是包含自己的那个结构)。指针的加减要注意类型,用(char*)ptr是为了计算字节偏移。((type *)0)->member是一个小技巧。自己理解吧。前面的(type *)再转回容器的类型。
===================================================================================
#define list_entry(ptr, type, member) /((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
ptr是指向list_head类型链表的指针,type为一个结构,而member为结构type中的一个域,类型为list_head,这个宏返回指向type结构的指针。在内核代码中大量引用了这个宏,因此,搞清楚这个宏的含义和用法非常重要。
设有如下结构体定义:
typedef struct xxx
{
……(结构体中其他域,令其总大小为size1)
type1 member;
……(结构体中其他域)
}type;
定义变量:
type a;
type * b;
type1 * ptr;
执行:
ptr=&(a.member);
b=list_entry(ptr,type,member);
则可使b指向a,得到了a的地址。
如何做到的呢?
先看&((type *)0)->member:
把“0”强制转化为指针类型,则该指针一定指向“0”(数据段基址)。因为指针是“type *”型的,所以可取到以“0”为基地址的一个type型变量member域的地址。那么这个地址也就等于member域到结构体基地址的偏移字节数。
再来看 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))):
(char *)(ptr)使得指针的加减操作步长为一字节,(unsigned long)(&((type *)0)->member)等于ptr指向的member到该member所在结构体基地址的偏移字节数。二者一减便得出该结构体的地址。转换为 (type *)型的指针,大功告成。
==============
list_entry定义如下:
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) //**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
===================================================================================
阅读全文
0 0
- list_entry()详解
- list_entry详解
- list_entry()详解
- list_entry()详解
- list_entry()详解
- list_entry详解
- list_entry()详解
- list_entry()详解
- list_entry()详解
- list_entry()详解
- list_entry()详解
- list_entry()详解
- list_entry()详解
- list_entry()详解
- list_entry()宏详解
- list_entry
- list_entry
- list_entry
- pt-table-check和pt-table-sync实践
- 情人节动画笔记
- 《并发编程》--15.线程安全的HashMap
- 表分区
- CDC派生类封装的GDI函数及功能说明
- list_entry()详解
- laravel查询数据库,对反馈回来的object类型,判断是否存在数据
- 欢迎使用CSDN-markdown编辑器
- 在日常工作中,认清最重要的事(笔记)
- 比特币 钱包这里唯一技术的体现就是冷钱包
- SpringCloud: 服务消费者(Feign)
- ViewPager + PhotoView-->图片查看器,类似今日头条图片查看
- js/jq 获取select下拉框的文本值和value值
- idea中使用MyBatis Generator逆向工程生成代码