【C 高阶】详解 container_of 宏

本文详细介绍了 Linux 内核中用于链表管理的 container_of 宏,通过实例解析其工作原理,包括双括号语法、typeof 关键字和结构体成员的地址偏移量。通过对 offsetof 和 container_of 宏的解剖,帮助读者理解如何通过结构体成员获取整个结构体的首地址。
摘要由CSDN通过智能技术生成

1. 简介

container_of 宏出现在 Linux 内核链表的管理程序中,其主要功能是通过结构体变量的任一成员便可得到该结构体变量的首地址。这是由于 Linux 内核链表被封装为一个单纯的链表结构类型,只要在结构体中定义了该链表结构类型的成员变量,该结构体类型便成为一个链表类型。因此,在链表中使用该宏可以快速地通过链表结构类型的结构体成员定位到成员所属的节点的地址!

container_of 宏源码为:

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

其中,ptr 为指向已知的结构体变量的成员的指针,type 为结构体的数据类型,member 为结构体成员名称。

offsetof 也为一个宏,源码为:

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

我相信绝大部分人没有见识过如此奇异的语法,如果有人能够一眼看懂这两个宏,那他的 C 语言修炼绝对是大师级别的。但大部分人还是看得是云里雾里的,根本不知所云,只能上网求助。本文我将通过原理结合实验的方法,带领大家一一解剖 container_of 宏!


2. 准备知识

看不懂宏里的语法,归根到底还是基础知识的欠缺,所以接下来好好补充一下 C 中的高阶知识吧!

2.1 双括号语法

container_of 宏中有两条明显的语句,其中第二条语句仅为一句减法语句,虽然对差值进行了强制类型转换,但并没有变量接收该差值,非常“诡异”!同时,宏的功能既然是得到结构体变量的首地址,则宏应该返回的是一个数值,但这里有两条完整的语句,宏替换后又怎么返回地址值呢?也非常“诡异”!

其实,这些“诡异”的状况都是双括号语法造成的。双括号语法为 GNU C 扩展的语法,形为 ({...}),在双括号体内允许包含任意多的完整的语句,并规定最后一条语句的结果便是该双括号体的返回值。

文字描述可能有些晦涩,那就直接通过程序体会体会!

  • 实验:
int main()
{
   
	int var = ({
   
		int tmp = 5;
		tmp * tmp;
	});
	printf("var = %d\n",var);   // var = 25
}

从实验可以看出,var 的初始化实际等价于 var = tmp * tmp;,即双括号体的返回值为最后一条语句的结果!

2.2 typeof 关键字

typeof 关键字为 GNU C 扩展的关键字,作用是提取修饰变量的数据类型,并把该数据类型替换到关键字所修饰的地方。例如:对于 int 型变量 numtypeof(num) 将被 “int” 替换掉。

  • 实验:
int main()
{
   
	char
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值