- 浏览: 208469 次
- 性别:
- 来自: 重庆
-
文章分类
最新评论
#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的成员地址,实际上就是它在结构中的偏移量。
发表评论
-
C++的原子操作
2012-12-20 17:43 4696在多进程(线程)访问资源时,能够确保所有其他的进程(线程 ... -
匿名namespace的作用以及它与static的区别
2012-12-20 17:24 1865一。匿名namespace的作用 在C语言中,如果我们 ... -
C++类型萃取技术
2012-12-19 15:16 1157Traits技术可以用来获得一个 类型 的相关信息的。 ... -
数值压缩存储方法Varint
2012-12-19 14:35 881转自:http://www.cnblogs.com/smark ... -
TypeList
2012-12-19 13:49 1162转自:http://blog.csdn.n ... -
template <unsigned int N>
2012-12-19 11:51 1508详见:http://stackoverflow.com/ ... -
二维指针*(void **)的研究(uC/OS-II案例)
2012-12-19 22:20 3308原文 : http://blog.csdn ... -
多级指针和链表
2012-12-18 22:28 0如果看到一个声明:t ... -
理解*(void**)b
2012-12-18 22:03 0#include <stdio.h> ... -
STL标准库:Allocator能做什么
2012-12-18 20:10 0The Standard Librarian: Wha ... -
三种的allocator实现源代码的对比
2012-12-18 19:55 1353转自:http://blog.csdn.net ... -
声明与函数、函数指针---(*(void (*)( ) )0)( ) 解析
2012-12-18 17:33 1122概述 在很 ... -
c++模板(类型依赖)说明例子
2012-12-18 16:57 1171#include <iostream> # ... -
C++中三种new的用法
2012-12-18 16:44 1843我评价自己的C++水平还未入门的确不够准确,应该是远远未 ... -
C++,永久改变你写异常安全代码的方式(神奇的Loki::ScopeGuard)
2012-12-17 20:19 2528作者:Andrei Alexandrescu and P ... -
C++的make_pair函数
2012-12-17 17:19 3536Pairs C++标准程序库中凡是“必须返回两 ... -
C++的explicit构造函数
2012-12-13 15:59 684按照默认规定,只有一个参数的构造函数也定义了一个隐式转换 ...
相关推荐
这样,每个 `person` 或 `animal` 实例不仅包含了年龄和体重等数据成员,还能通过 `list` 成员与其他实例形成双向链表结构。 #### 三、`list_head` 相关函数介绍 `<linux/list.h>` 头文件中提供了一系列用于操作...
本篇文章将深入探讨这种数据结构,包括`list_head`、`list_entry`以及相关的遍历宏`list_for_each`。 首先,我们要理解什么是双向循环链表。不同于单向链表,双向循环链表中的每个节点不仅包含指向下一个节点的指针...
本文将详细介绍 Linux 内核中的两种主要链表结构:list 和 hlist,并解释与之相关的宏及其用法。 #### 2. 通用宏 ##### 2.1. typeof **2.1.1. 定义** `typeof` 并不是一个宏,而是 GCC 的一个内建操作符,用于...
list_head 结构可以作为一个成员嵌入到宿主数据结构内,可以将链表结构放在宿主结构内的任何地方,宿主结构可以有多个链表结构,并可以用 list_head 中的成员和相对应的处理函数来对链表进行遍历。 3. 定义和初始化...
本篇文章将详细讲解Tkinter中的两个关键组件——Entry和Text,并通过示例代码展示它们的添加与使用方法。 首先,我们来看Entry组件。Entry是用于创建单行文本输入框的控件,用户可以在其中输入或修改文本。在示例...
在UEFI中,Protocol的组织方式是通过LIST_ENTRY结构体来实现的,LIST_ENTRY结构体将IHANDLE、PROTOCOL_ENTRY、PROTOCOL_INTERFACE、PROTOCOL_NOTIFY这些结构体“串连”起来,形成一个链表。这样,我们可以通过LIST_...
- `list_entry(ptr, type, member)`:通过成员变量`member`从结构体指针`ptr`获取`type`类型的对象指针。 - `list_for_each(pos, head)`:遍历链表`head`,用`pos`迭代每个节点。 - `list_for_each_entry(pos, ...
链表的遍历通常使用`list_for_each_entry`和`list_for_each_entry_reverse`等循环宏,它们允许我们方便地访问链表中的每一个元素。在内核编程中,这样的链表操作非常常见,例如用于管理内存分配的slab缓存系统、设备...
内核链表还提供了用于访问链表节点的宏,比如list_entry宏可以根据list_head结构的地址,计算出宿主数据结构的地址。这些宏在遍历链表和操作链表时非常有用。 在实际使用中,内核链表能够高效地对数据进行管理,...
本书不仅说明了插口API和协议族的关系以及主机实现与路由器实现的差别。还介绍了4.4BSD-Lite版的新的特点,如多播、长肥管道支持、窗口缩放、时间戳选项以及其他主题等等。读者阅读本书时,应当具备卷1中阐述的关于...
在这个结构体中,有一个名为ActiveProcessLinks的LIST_ENTRY变量,它是EPROCESS结构体在系统中所有进程列表中的链接字段。这个列表是由内核维护的,用于跟踪系统中的每一个活动进程。 LIST_ENTRY是一个双向链表结构...
遍历内核链表可以使用`for_each_entry`或`for_each_entry_safe`宏。前者在遍历时不允许删除当前节点,而后者通过临时变量保护,可以在遍历过程中安全地删除节点。 5. **链表操作的原子性**: 在多线程环境下,...
- **g_mmipb_entry_list**:表示存储器中排序和entry_id使用情况的数据结构。 - `MMIPB_PHONEBOOK_SORT_T sort_t`:用于排序的表格。 - `MMIPB_ENTRY_ID_T sim_entry_id_t`:SIM卡中entry_id的使用情况。 - `...
`list_for_each_entry(pos, head, member)`循环遍历链表,`pos`是链表节点类型变量,`head`是链表头,`member`是链表节点类型中包含`list_head`的成员名。这确保了即使在遍历过程中删除节点,也不会发生未定义的行为...
文件中提到了list_head结构体,这是内核链表的节点结构,而list_for_each()、list_entry()等宏用于遍历链表和从链表中提取元素。这些宏是内核中常用的链表操作工具。 由于提供的文件片段中存在部分OCR扫描错误和不...
接下来,你可以遍历RAR文件中的所有条目,使用`rar_list`函数获取条目列表,并使用`rar_entry_get`获取特定条目。如果条目是目录,可以使用`rar_entry_extract`解压到服务器上的目标目录: ```php $entries = rar_...
7. 易语言语法:熟悉易语言的基本语法规则,如变量声明、函数调用、流程控制等。 8. 实践应用:通过编写简单的程序,练习使用PeLoader支持库来加载和控制PE文件,提升对Windows程序运行机制的理解。 9. 安全与反反...
3. **长度信息**:`size`内置变量可以获取list的长度,`last`变量表示是否是最后一个元素。 ```freemarker <#list users as user> 这是最后一个用户: ${user.name} </#list> ``` 4. **遍历子列表**:`...
其中,id_table可以使用宏PCI_DEVICE(VENDOR_ID, DEVICE_ID)进行初始化,VENDOR_ID和DEVICE_ID分别是设备和厂商编号,由板卡生产厂家指定。 3. struct pci_dev数据结构 struct pci_dev是Linux内核中用于描述PCI...