首页 > 编程知识 正文

offsetof宏,使用宏组的目的是

时间:2023-05-06 08:58:51 阅读:115958 作者:2371

文章目录回顾问题具象化上的工具offsetof实例分析container_of实例分析offsetof原理container_of原理参考

回头看

上一篇文章讨论了3358www.Sina.com/和内核链表之间的区别,但是内核链接是如何在普通链表上实现的这篇文章我们来解答这个问题。

问题具象化上述问题可以具体记述如下。

有结构体变量led

struct led_dev {char *name; int brightness; 结构列表_头链接; Int标志; (; 结构led _ dev led; 变量led不在当前代码的范围内,无法直接操作成员(可以理解为led变量位于单独的. c文件中,当前. c无法获得此变量并直接使用)。

我知道led.link的地址,需要多少led的地址?

访问该工具时,将使用linux内核提供的两个宏

#defineoffsetof(type,MEMBER ) ) size_t ) ) TYPE * )0)-MEMBER ) ) define container _ of (ptr,type,MEMBER ) ) ((type * ) ) char*__mptr-offsetof ) type,member ); } )简单介绍一下。

offsetof宏用于计算结构中成员变量的偏移。

container_of宏用于在给定变量的结构类型和该变量成员的地址的条件下计算该变量的地址。

offsetof实例分析# include stdio.h # include stdint.h # include stdlib.h # define offset of (type *,MEMBER ) ) size_t struct led_dev {char *name; int brightness; 结构列表_头链接; Int标志; (; int main () {size_t off_set=0; off _ set=offset of (结构led _ dev,name; printf(off_setofname=%LDn ),off_set ); off _ set=offset of (结构led _ dev,brightness ); printf (off_set of brightness=% LDn ),off _ set ); off _ set=offset of (结构led _ dev,link ); printf(off_setoflink=%LDn ),off_set ); off _ set=offset of (结构led _ dev,flags ); printf(off_setofflags=%LDn ),off_set ); 返回0; }运行输出

off _ seto fname=0off _ set of brightness=8off _ seto flink=16 off _ setofflags=32 name是结构的第一个元素,因此其偏移量为0brightness 因此,brightness的偏移量为8。 同样,link的偏移量可以求出为16。 flags的偏移为32 container_of实例分析# include stdio.h # include stdint.h # include stdlib.h # define offset of (类型, member((size_t ) ) TYPE *)-MEMBER )/* * container _ of-castamemberofastructureouttothecontaingstruction @ @ type : thetypeofthecontainerstructthisisembeddedin.* @ member 3360 thenameofthememberwithinthestruct.* */# define cone

ptr - offsetof(type,member) );})struct list_head {struct list_head *next, *prev;};struct led_dev {char *name;int brightness;struct list_head link;int flags;};struct led_dev led = {"green",1,{NULL, NULL},0xFF,};int main(){printf("led address : %pn", &led); // 打印 led 的地址,这里仅仅打印,用来和后面计算的结果进行正确性对比,因为场景是 led 地址我们是不知道的。printf("led.link address : %pn", &led.link); // 假设通过链表拿到了下一个节点的指针域的地址:&led.link (隐含信息 &led.link = &led.link.next)// 下面就想办法通过这个地址来推出节点的首地址,进而也就知道了所有成员的地址struct led_dev *ptr = container_of(&(led.link), struct led_dev, link);printf("ptr address : %pn", ptr);// 检查 ptr 的地址是否和 led 的地址相同,想同的话,就表示我们成功拿到了 led 的地址。后面就能使用 ptr 来访问结构体中的其它成员变量了printf("ptr->name = %sn", ptr->name);printf("ptr->brightness = %dn", ptr->brightness);printf("ptr->flags = 0x%xn", ptr->flags);return 0;}

运行结果

led address : 0x55745d380020led.link address : 0x55745d380030ptr address : 0x55745d380020ptr->name = greenptr->brightness = 1ptr->flags = 0xff 我们定义了一个 led 变量,不过这里我们假设 led 变量是在别处定义的,我们拿不到。main 函数第一句仅仅是打印其地址,用作和后面求得的 led 变量地址做正确性验证。我们已知 led 的一个成员变量的地址,即 led.link 的地址我们的目的是通过 led.link 的地址求 led 的地址

struct led_dev *ptr = container_of(&(led.link), struct led_dev, link);

可以看到,上述这句就是得到 led 地址的语句,入参是:led.link 的地址,led 的结构体类型,成员
返回结果:led 变量的地址。

从运行结果也可以看到,我们已知 led.link 的地址为 0x55745d380030,求得 led 的地址为 0x55745d380020,和代码一开始打印的 led 的地址相同,故结果正确。

offsetof 原理

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

对于这个宏,我们逐层去理解

1. 02. (TYPE *)03. ((TYPE *)0)->MEMBER4. &((TYPE *)0)->MEMBER5. (size_t) &((TYPE *)0)->MEMBER

1、内存地址开始于 0
2、将 0 转换成 TYPE 类型的结构体指针,换句话说就是让编译器认为这个结构体开始于程序段的起始位置
3、引用结构体中的 MEMBER 成员
4、取地址
5、将取到的地址强制转换为 size_t 类型

因为这个结构体的起始地址被指定为 0,所以取到的结构体成员的绝对地址(当转换为数字)就是这个成员在结构体中的偏移量。

这个代码之所以没有风险,是因为这里没有对任何内存进行写操作,甚至没有读操作。只是操作了指向这些位置的指针,而指针一般存储在机器寄存器或是通常的本地堆栈。

container_of 原理 #define container_of(ptr, type, member) ({const typeof( ((type *)0)->member ) *__mptr = (ptr);(type *)( (char *)__mptr - offsetof(type,member) );})

同样进行逐层分析

1. 02. (type *)03. ((type *)0)->member4. typeof( ((type *)0)->member )5. typeof( ((type *)0)->member ) *__mptr6. typeof( ((type *)0)->member ) *__mptr = (ptr);7. (type *)( (char *)__mptr - offsetof(type,member) );

1、2、3、 同 offsetof
4、typeof 获取变量类型
5、使用获取到的类型定义一个临时指针变量 __mptr
6、将传入的成员变量地址赋值给 __mptr
7、用 __mptr 减去成员在结构体中的偏移量,就得到了结构体变量的地址

参考

stackoverflow

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。