list_entry(ptr, type, member)——知道结构体内某一成员变量地址,求结构体地址
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr) - (unsigned long)(&((type *)) -> member)))
解释:
1 在0这个地址看做有一个虚拟的type类型的变量,那么取一个成员再取这个成员的地址,就是这个结构体中这个成员的绝对地址 。
2 这句话的意思是获取一个结构体中一个成员在这个结构体中的偏移。type *0是为了计算地址方便。
意思是在0这个地址看做有一个虚拟的type类型的变量,那么取一个成员再取这个成员的地址,就是这个结构体中这个成员的绝对地址,
由于结构体在地址为0的地方,所以这个成员在这个结构体中的相对位置也是这个值了。ptr可能是这个member的指针,而现在想找这
个member所在结构体的地址,所以这个member的地址应该减去这个member在这个结构体中的偏移。然后返回这个结构体类型。
3 实例分析
typedef struct
{
int i;
int j;
}exp;
这个exp结构体占用8个字节,假设声明一个变量。
exp e1;
那么假如已知e1.j的地址,想知道e1的地址该如何办呢?只要知道j在e1中的偏移,然后把j的地址减去这个偏移就是e1的地址了。在这里,i占据的前4个字节,所以j占据了5-8的字节。现在我们用你给出的list_entry来解释一下。
int *p = e1.j;
假设e1的地址是0x100,那么p就是0x104。可是如何才能比较方便的知道p减去4就是e1的地址呢?尤其是我们可能有时候不知道exp这个结构体里面具体什么样子的。下面的
list_entry(p, exp, j);
变成:
(exp *)((char *)p-(unsigned long)(&((exp *)0)->j))
(exp *)0在0地址上面建立8个字节的exp结构体,->j取出这个0地址上exp结构体里的j成员,&((exp *)0)->j)把这个成员地址取出来,由于j在这个结构体里是在5-8字节,所以从0地址数5个字节就是j所在的位置。这种方法省去了我们需要预先知道结构体具体什么样子,结构体里成员的位置怎么安排的。p的地址再减去我们刚算出来j所在的位置,就得到e1的地址。
也就是:
&e1 == list_entry(p, exp, j)
list_entry(ptr, type, member)——知道结构体内某一成员变量地址,求结构体地址的更多相关文章
- 对list_entry(ptr, type, member)的理解
如何根据一个结构体成员的地址.结构体类型以及该结构体成员名获得该结构体的首地址? #define list_entry(ptr, type, member) \ ((type *)((char *)( ...
- (转)内核container_of(ptr,type,member) 解析
container_of(ptr,type,member) 用于在已知结构体里面成员member和该成员指针ptr(就是地址)和结构体类型type, 返回该成员所在的结构体的指针(就是地址), 例如 ...
- 由结构体成员地址计算结构体地址——list_entry()原理详解
#define list_entry(ptr, type, member) container_of(ptr, type, member) 在进行编程的时候,我们经常在知道结构体地址的情况下,寻找其中 ...
- Linux中的两个经典宏定义:获取结构体成员地址,根据成员地址获得结构体地址;Linux中双向链表的经典实现。
倘若你查看过Linux Kernel的源码,那么你对 offsetof 和 container_of 这两个宏应该不陌生.这两个宏最初是极客写出的,后来在Linux内核中被推广使用. 1. offse ...
- 结构体内的函数与bfs的情景变量
关于结构体内的函数,太难的尚且不会用,下面是一个简单一点的结构体内函数的代码 定义这样一个结构体函数之后就能像如下这样使用了 以上为结构体内的简单函数,下面重点来了,关于bfs找最短路由于需要避免走回 ...
- struct结构体内存大小
一. 基本原则 1. struct中成员变量的声明顺序,与成员变量对应的内存顺序是一致的: 2. struct本身的起始存储地址必须是成员变量中最长的数据类型的整倍数,注意是最长的数据类型,而不是最长 ...
- C++ struct结构体内存对齐
•小试牛刀 我们自定义两个结构体 A 和 B: struct A { char c1; char c2; int i; double d; }; struct B { char c1; int i; ...
- 通过 struct 成员地址 获取 struct 结构体地址
1. 问题描述: 现在定义了一个结构体: struct Foo { int a; int b; }; Foo foo; 假如由于函数传参等原因,现在程序只能拿到 foo.b 的地址,这时想通过某种方法 ...
- nginx取结构体地址
linux内核提供了一个container_of()宏,可以根据结构体某个成员的地址找到父结构的地址. #define container_of(ptr, type, member) ({ \ con ...
随机推荐
- nyoj(表达式求值)
描述 ACM队的mdd想做一个计算器,但是,他要做的不仅仅是一计算一个A+B的计算器,他想实现随便输入一个表达式都能求出它的值的计算器,现在请你帮助他来实现这个计算器吧. 比如输入:"1+2 ...
- Binary Tree Longest Consecutive Sequence -- LeetCode
Given a binary tree, find the length of the longest consecutive sequence path. The path refers to an ...
- DP套DP
DP套DP,就是将内层DP的结果作为外层DP的状态进行DP的方法. [BZOJ3864]Hero meet devil 对做LCS的DP数组差分后状压,预处理出转移数组,然后直接转移即可. tr[S] ...
- Luogu P3960 列队 线段树
题面 线段树入门题. 我们考虑线段树来维护这个矩阵. 首先我们先定n+1棵线段树前n棵维护每行前m-1个同学中没有离队过的同学,还有一棵维护第m列中没有离队过的同学.再定n+1棵线段树前n棵线段树维护 ...
- java之判断输入的数是否为素数
import java.util.Scanner; public class TestIsSushu { public static void main(String[] args) { Scanne ...
- Xcode 6.4项目中的常见文件(info.plist)
Xcode 6.4项目中的常见文件(info.plist) 代码中获取 info.plist[NSBundle mainBundle] infoDictionary]; Bundle display ...
- [bug]超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。
引言 自己弄了一个小项目——日程管理系统,在初始化日期时,查询了数据库,每个日期就会查询一次数据库,就导致了这个问题. 问题 出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小. Desc ...
- 使用Git代替FTP进行虚拟主机的代码管理
为什么要使用Git代替FTP的原因: 由于本人菜鸟+穷屌,玩不起VPS和其他大牌的云主机,所以呢就只能在景安(这不是广告..)申请了免费的虚拟主机,就想着自己玩玩而已,免费的嘛,空间流量什么的就不讨论 ...
- 基于tiny4412的Linux内核移植 -- DM9621NP网卡驱动移植(四)
作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...
- Oracle数据库查看用户状态
一.当前ORACLE用户的状态可查看视图DBA_USERS;一般情况下在使用的正常用户均处于OPEN状态. 1 SQL> select username,account_status from ...