一年后再次回头看container_of宏的作用

简介: container_of宏在很久以前的文章我就已经有分析写过了,但是看回去,感觉以前自己对这个宏的表达描述分析能力还是有待提高,毕竟那时候刚接触linux内核不久,整个人都懵懵哒,无法说得让别人通俗易懂。

container_of宏在很久以前的文章我就已经有分析写过了,但是看回去,感觉以前自己对这个宏的表达描述分析能力还是有待提高,毕竟那时候刚接触linux内核不久,整个人都懵懵哒,无法说得让别人通俗易懂。

那么这个宏整体是什么样子的呢?

//获取结构体成员相对于结构体的偏移 
#define offsetof(TYPE,MEMBER) ((int) &((TYPE *)0)->MEMBER)  
//通过获取结构体中的某个成员,反推该结构体的指针 
#define container_of(ptr, type , member) ({ \
	const typeof(((type *)0)->member) *__mptr = (ptr) ; \
	(type *)((char *)__mptr - offsetof(type,member)) ;})
作用:通过某个结构体中的某个成员变量的指针,反推这个结构体变量的指针。说白了,我定义一个结构体变量和结构体指针,变量.结构体中某一个成员(这个我是知道的),还有知道它的地址,也就是&(变量.结构体中某一个成员),通过这两个参数,还有结构体的type,返回得到的就是结构体的首地址。

工作原理:

先用typeof获取变量的数据类型,也就是member成员的类型,然后将member这个成员 的指针转成自己类型的指针,再从offsetof相减,就得到整个结构体变量的首地址了,再将该地址强制转化为type *。

关于offsetof的作用就不再阐述,文章超链接在这:Offsetof宏的作用和原理

接下来看看如何使用吧,也很简单。

#include <stdio.h>  
#include <stdlib.h>
//获取结构体成员相对于结构体的偏移 
#define offsetof(TYPE,MEMBER) ((int) &((TYPE *)0)->MEMBER)  
//通过获取结构体中的某个成员的,反推该结构体的指针 
#define container_of(ptr, type , member) ({ \
	const typeof(((type *)0)->member) *__mptr = (ptr) ; \
	(type *)((char *)__mptr - offsetof(type,member)) ;})

#pragma pack(4)  
struct ptr  
{  
    char a ;   
    short b ;   
    int  c ;   
    double d ;  
};  
#pragma pack()  
int main(void)  
{  
    struct ptr Pt ;  
    struct ptr *pt ;
    printf("ptr:%d\n",sizeof(struct ptr));//16  
    //获取结构体的首地址 
    printf("ptr:%p\n",&Pt); //0028FEA8
    Pt.a = 'a';
    Pt.b = 2 ;
    Pt.c = 4 ;
    Pt.d = 12.04 ;
    //通过container_of获取结构体的首地址 
    pt = container_of(&Pt.c, struct ptr , c);
    printf("pt:%p\n",pt);  //0028FEA8
    printf("a:%c\n",pt->a) ;  //'a'
    printf("b:%d\n",pt->b) ;  //2
    printf("c:%d\n",pt->c) ;  //4
    printf("d:%.2lf\n",pt->d);//12.04
    return 0 ;  
}  



目录
相关文章
|
6月前
|
Web App开发 JavaScript API
ng-template 使用过程中参数传递错误的单步调试
ng-template 使用过程中参数传递错误的单步调试
40 0
|
6月前
|
JSON JavaScript 数据格式
ng-template 使用过程中默认参数不能按照期望工作的问题单步调试
ng-template 使用过程中默认参数不能按照期望工作的问题单步调试
22 0
|
1月前
解释一下什么是VIF。
解释一下什么是VIF。
47 0
|
8月前
|
JavaScript 前端开发
v-show和v-if指令的共同点和不同点?
v-show和v-if的共同点 两者都能控制元素在页面是否显示 在用法上也是相同的
|
8月前
|
JavaScript 前端开发 UED
js事件的作用和用法
js事件的作用和用法
66 0
|
9月前
|
Kubernetes API 微服务
一文搞懂 Container 运行原理
当我们开始学习 Kubernetes 时,我们并不完全清楚每个 Pod 是如何分配 IP 地址以及微服务容器化后是如何正常工作。或许,我们可能或多或少了解各个组件的概念以及它们是如何独立工作。但是,在特定的环境下可能不清楚这些组件是如何关联起来。
95 0
|
11月前
|
NoSQL Java 数据库
解释afterPropertiesSet方法的用处
解释afterPropertiesSet方法的用处
|
Linux iOS开发
查看宏展开后的代码
查看宏展开后的代码
522 0
#define 定义宏 概念和函数的优缺点,使用条件 #undef 宏的副作用 宏使用时的“潜规则“
#define 定义宏 概念和函数的优缺点,使用条件 #undef 宏的副作用 宏使用时的“潜规则“
116 0
|
JavaScript
分不清bind、apply、call?手写实现一下就明白了
bind、call和apply都是`Function`原型链上面的方法,因此不管是使用`function`声明的函数,还是箭头函数都可以直接调用。这三个函数在使用时都可以改变`this`指向,本文就带你看看如何实现bind、call和apply。
95 0
分不清bind、apply、call?手写实现一下就明白了