`

结构体内变量相对便宜与list_entry()宏

    博客分类:
  • c++
阅读更多

 

#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 - 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) \

 

   ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

 

--------------------------------------------------------------------------------------------------

 

指针ptr指向结构体type中的成员member;通过指针ptr,返回结构体type的起始地址,如图2。

 

 

 

type

 

        |----------|

 

        | |

 

          | |

 

          |----------|

 

ptr--> | member --|

 

          |----------|

 

          | |

 

        | |

 

         |----------|

 

        图2 list_entry()宏的示意图

 

为了便于理解,在此给予进一步说明。

 

例如my_list结构:

 

struct my_list{

 

void *mydata;

 

struct list_head list;

 

}; struct list_head *pos;  

 

则list_entry(pos, mylist, list)宏,就可以根据pos的值,获取mylist的地址,也就是指向mylist的指针,这样,我们就可以存取mylist->mydata字段了。

 

可为什么能够达到这样的效果?

 

list_entry(pos, mylist, list) 展开以后为:

 

((struct my_list *)((char *)(pos) - (unsigned long)(&((struct my_list *)0)->list)))

 

这看起来会使大多数人眩晕,但仔细分析一下,实际很简单。

 

((size_t) &(type *)0)->member)把0地址转化为type结构的指针,然后获取该结构中member成员的指针,并将其强制转换为size_t类型。于是,由于结构从0地址开始定义,因此,这样求出member的成员地址,实际上就是它在结构中的偏移量。

分享到:
评论

相关推荐

    TCP-IP详解卷2:实现.part1

    本书不仅说明了插口API和协议族的关系以及主机实现与路由器实现的差别。还介绍了4.4BSD-Lite版的新的特点,如多播、长肥管道支持、窗口缩放、时间戳选项以及其他主题等等。读者阅读本书时,应当具备卷1中阐述的关于...

    drgn:可编写脚本的调试器库

    >>> from drgn.helpers.linux import list_for_each_entry >>> for mod in list_for_each_entry( ' struct module ' , ... prog[ ' modules ' ].address_of_(), ... ' list ' ): ... if mod.refcnt.counter > 10 : ....

    xmine c++资源

    (gdb) print find_entry(1,0) l 数据结构和其他复杂对象 (gdb) print *table_start $8={e=reference=’\000’,location=0x0,next=0x0} l 值的历史成分 (gdb)print $1 ($1为历史记录变量,在以后可以直接引用 $1 的值)...

    获取当前进程的列表

    //创建进程信息变量,用于保存信息 info->dwSize=sizeof(PROCESSENTRY32); //设置块大小 int i=0; if(Process32First(handle,info))//开始枚举进程 { if(GetLastError()==ERROR_NO_MORE_FILES ) { ...

    驱动程序设计基础专题-filedisk源码分析

    LIST_ENTRY list_head; KSPIN_LOCK list_lock; KEVENT request_event; PVOID thread_pointer; BOOLEAN terminate_thread; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; media_in_device是指这个设备是否已经...

    最全的oracle常用命令大全.txt

    可以使用DEFINE命令设置系统变量EDITOR来改变文本编辑器的类型,在login.sql文件中定义如下一行 DEFINE_EDITOR=vi f、运行命令文件 SQL>START test SQL>@test 常用SQL*Plus语句 a、表的创建、修改、删除 创建表的...

    windbg资料集合

    +0x010 ThreadListEntry : _LIST_ENTRY [ 0xff70fbd0 - 0xff70fbd0 ] +0x018 IoStatus : _IO_STATUS_BLOCK +0x020 RequestorMode : 1 '' +0x021 PendingReturned : 0 '' +0x022 StackCount : 1 '' +0x023 ...

    2009 达内Unix学习笔记

    ls -l (list)列表显示文件(默认按文件名排序), 显示文件的权限、硬链接数(即包含文件数,普通文件是1,目录1+)、用户、组名、大小、修改日期、文件名。 ls -t (time)按修改时间排序,显示目录和文件。 ls -lt 是...

    uboott移植实验手册及技术文档

    其调用与 CFG_NAND_LEGACY 宏有 关,如果没有定义这个宏,系统调用 drivers/nand/nand.c 中的 nand_init();否则调用自己在 本文件中的 nand_init()函数,本例使用后者。fs2410.c代码如下: #if defined(CONFIG_CMD...

    Windows内核安全与驱动开发光盘源码

    3.2.2 使用LIST_ENTRY 41 3.2.3 使用长长整型数据 43 3.3 自旋锁 44 3.3.1 使用自旋锁 44 3.3.2 在双向链表中使用自旋锁 45 3.3.3 使用队列自旋锁提高性能 46 第4章 文件、注册表、线程 47 4.1 文件操作 47 ...

    grub4dos-V0.4.6a-2017-02-04更新

    setmenu --graphic-entry=类型=菜单行数=菜单列数=图形宽(像素)=图形高(像素)=菜单行间距(像素) 菜单项0的路径文件名 类型: 位0:高亮指定颜色 位1:高亮颜色翻转 位2:高亮显示线框 位7:背景透明(最好使用黑色...

    ip地址库 很全的库

    // 为提高效率而采用的临时变量 private IPLocation loc; private byte[] buf; private byte[] b4; private byte[] b3; private String province = null; private String city = null; private ...

    PHP基础教程 是一个比较有价值的PHP新手教程!

    2.5 变量与常量 可能你已经注意到,变量都有一个美元符号($)的前缀。所有变量都是局部变量,为了使得定义的函数中可以使用外部变量,使用global语句。而你要将该变量的作用范围限制在该函数之内,使用static语句...

    Windows内核安全驱动开发(随书光盘)

    3.2.2 使用LIST_ENTRY 41 3.2.3 使用长长整型数据 43 3.3 自旋锁 44 3.3.1 使用自旋锁 44 3.3.2 在双向链表中使用自旋锁 45 3.3.3 使用队列自旋锁提高性能 46 第4章 文件、注册表、线程 47 4.1 文件操作 47 ...

    在JSTL EL中处理java.util.Map,及嵌套List的情况

    当forEach 的items属性中的表达式的值是java.util.Map时,则var中命名的变量的类型就是 java.util.Map.Entry。这时var=entry的话,用表达式${entry.key}取得键名。 用表达${entry.value}得到每个entry的值。这是...

    Ethercat-Ighmaster.txt

    根据实际情况修改build_ethercat-1.5.2.sh中以下几个变量: output_dir='output' #编译输出目录 module_install_dir='module_install' #内核模块安装目录 kernel_source_dir='/mnt/fs_ext/imx6/linux-3.0.35' ...

    root_utils:具有选择索引的 TChain

    用法示例: chain = IndexedChain(treename)chain.Add(filename)chain.retrieve_entrylists([cut1, cut2, cut3])# loop on cut, then loop on entryfor cut in chain.tcuts_with_existing_list(): chain.preselect...

    深入解析Windows操作系统中文.part2.rar

    检查与进程、线程和作业相关的数据结构和算法;观察Windows如何管理虚拟内存和物理内存;理解NTFS的操作和格式,诊断文件系统访问问题;从上往下查看Windows的网络栈,包括映射、API、名称解析和协议驱动程序;诊断...

    Java容器.xmind

    List 标记: interface ArrayList 标记: class CRUD : boolean add​(E e) boolean remove​(Object o) E set​(int index, E element) E get​(int index) 底层数组实现,查询快,增删慢 LinkedList 标记: ...

    《你必须知道的495个C语言问题》

    2.8 我听说结构可以赋给变量也可以对函数传入和传出。为什么K&R1却明确说明不能这样做? 25 2.9 为什么不能用内建的==和!=操作符比较结构? 26 2.10 结构传递和返回是如何实现的? 26 2.11 如何向接受结构参数...

Global site tag (gtag.js) - Google Analytics