广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言宏函数containerof()简介
  • 832
分享到

C语言宏函数containerof()简介

2024-04-02 19:04:59 832人浏览 薄情痞子
摘要

在linux 内核编程中,会经常见到一个宏函数container_of(ptr,type,member), 但是当你通过追踪源码时,像我们这样的一般人就会绝望了(这一堆都是什么呀?

linux 内核编程中,会经常见到一个宏函数container_of(ptr,type,member), 但是当你通过追踪源码时,像我们这样的一般人就会绝望了(这一堆都是什么呀? 函数还可以这样定义??? 怎么还有0呢???  哎,算了,还是放弃吧。。。)。 这就是内核大佬们厉害的地方,随便两行代码就让我们怀疑人生,凡是都需要一个过程,慢慢来吧。

其实,原理很简单:  已知结构体type的成员member的地址ptr,求解结构体type的起始地址。

type的起始地址 = ptr - size (这里需要都转换为char *,因为它为单位字节)。

到此,该函数已经讲完,是不是很简单??? 其实也不是,这里并没有提到size如何计算,而令我们头晕的正是这里。

好吧,先上container of函数原型:


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

其次为 offserof 函数原型:


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

怎么样,是不是很炫?  好吧,下面开始揭开面纱:

(一)0 指针的使用    (自己给的名字,不知有木问题)

让事实说话:


#include<stdio.h>
 
struct test
{
	char i ;
	int j;
	char k;
};
 
int main()
{
	struct test temp;
	printf("&temp = %p\n",&temp);   
	printf("&temp.k = %p\n",&temp.k);
	printf("&((struct test *)0)->k = %d\n",((int)&((struct test *)0)->k));
 
}

编译运行,可以得到如下结果:


&temp = 0xbf9815b4
&temp.k = 0xbf9815bc
&((struct test *)0)->k = 8

什么意思看到了吧,自定义的结构体有三个变量:i,j,k。 因为有字节对齐要求,所以该结构体大小为4bytes * 3 =12 bytes.   而&((struct test *)0)->k 的作用就是求 k到结构体temp起始地址的字节数大小(就是我们的size)。在这里0被强制转化为struct test *型, 它的作用就是作为指向该结构体起始地址的指针,就是作为指向该结构体起始地址的指针,就是作为指向该结构体起始地址的指针, 而&((struct test *)0)->k  的作用便是求k到该起始指针的字节数。。。其实是求相对地址,起始地址为0,则&k的值便是size大小(注:打印时因为需要整型,所以有个int强转)所以我们便可以求我们需要的 size 了  。 好吧,一不小心把 offsetof() 函数的功能给讲完了:::


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

这次再看就顺眼了吧(底层为什么是这样我还是不懂。。。只知道这样确实可以) ,  所以offsetof()的作用就是求我们梦寐以求的size, 并以size_t形式返回(size_t: 无符号整型)。

(二)内核编程的严谨性


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

这里我们只看第二行:


const typeof( ((type *)0)->member ) *__mptr = (ptr);  

它的作用是什么呢? 其实没什么作用(勿喷勿喷,让我把话说完),但就形式而言 _mptr = ptr,  那为什么要要定义一个一样的变量呢??? 其实这正是内核人员的牛逼之处:如果开发者使用时输入的参数有问题:ptr与member类型不匹配,编译时便会有warnning, 但是如果去掉改行,那个就没有了,而这个警告恰恰是必须的(防止出错有不知道错误在哪里)。。。这严谨性可以吧


typeof( ((type *)0)->member )

它的作用是获取member的类型仅此而已。至此基本结束

(三) 总结

container_of(ptr, type,member)函数的实现包括两部分:

  • 1.判断ptr 与 member 是否为同意类型
  • 2.计算size大小,结构体的起始地址 = (type *)((char *)ptr - size)   (注:强转为该结构体指针)

现在我们知道container_of()的作用就是通过一个结构变量中一个成员的地址找到这个结构体变量的首地址。

container_of(ptr,type,member),这里面有ptr,type,member分别代表指针、类型、成员。

到此这篇关于C语言宏函数container of()简介的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: C语言宏函数containerof()简介

本文链接: https://www.lsjlt.com/news/160254.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言宏函数containerof()简介
    在linux 内核编程中,会经常见到一个宏函数container_of(ptr,type,member), 但是当你通过追踪源码时,像我们这样的一般人就会绝望了(这一堆都是什么呀? ...
    99+
    2022-11-12
  • C语言函数与宏怎么使用
    这篇文章主要讲解了“C语言函数与宏怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C语言函数与宏怎么使用”吧!一、函数与宏宏是由预处理器直接替换展开的,编译器不知道宏的存在函数是由编译...
    99+
    2023-06-30
  • C语言宏函数container of()怎么使用
    本篇内容主要讲解“C语言宏函数container of()怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C语言宏函数container of()怎么使用”吧!在lin...
    99+
    2023-06-22
  • C语言中宏和函数的区别有哪些
    这篇文章主要介绍了C语言中宏和函数的区别有哪些的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C语言中宏和函数的区别有哪些文章都会有所收获,下面我们一起来看看吧。C语言中的宏和函数是非常相似的,它们都可以完成类似...
    99+
    2023-07-05
  • C语言深入分析函数与宏的使用
    目录一、函数与宏二、宏的妙用三、小结一、函数与宏 宏是由预处理器直接替换展开的,编译器不知道宏的存在函数是由编译器直接编译的实体,调用行为由编译器决定多次使用宏会导致最终可执行程序的...
    99+
    2022-11-13
  • C语言中宏和函数的9个区别详解
    目录1.代码长度2.执行速度3.操作符优先级4.带有副作用的参数5.参数类型6.调试7.递归8.命名约定9.其他总结C语言中的宏和函数是非常相似的,它们都可以完成类似的功能。比如,想...
    99+
    2023-05-14
    C语言 函数区别 C语言 函数 C语言 C语言 函数
  • C语言中函数宏封装的方式有哪些
    本篇内容介绍了“C语言中函数宏封装的方式有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. 函数宏介绍函数宏,即包含多条语句的宏定义,...
    99+
    2023-07-05
  • 详解C语言中函数宏的三种封装方式
    目录1. 函数宏介绍2. {} 方式3. do{...}while(0) 方式4. ({}) 方式5. 总结1. 函数宏介绍 函数宏,即包含多条语句的宏定义,其通常为某一被频繁调用的...
    99+
    2023-03-20
    C语言函数宏封装 C语言函数宏 C语言宏
  • 介绍C语言中tolower函数的实例
    C语言tolower函数用于把大写字母转换为小写字母。 在本文中,我们先来介绍tolower函数的使用方法,然后编写一个自定义的_tolower函数,实现与tolower函数相同的功...
    99+
    2022-11-12
  • C语言中函数的介绍及用法
    本篇内容介绍了“C语言中函数的介绍及用法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!目录函数定义库函数定义介绍Example 1 strc...
    99+
    2023-06-20
  • C++中的atoi 函数简介
    目录一.atoi 函数二.atoi 函数函数实战 一.atoi 函数 在 stdlib.h 中 atoi 函数,可用于将 char 字符串转为 int 整数类型, 语法如下: ...
    99+
    2022-11-12
  • C语言回调函数的简单运用
    目录一、什么是回调函数二、简单的回调函数三、带参数的回调函数一、什么是回调函数 因为在程序中,我们有很多的库函数,我们也有很多的上层函数,为了增加程序的灵活性,我们就将一些函数指针作...
    99+
    2022-11-12
  • C语言中字符函数和字符串函数介绍
    本篇内容介绍了“C语言中字符函数和字符串函数介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!目录前言求字符串长度strlen介绍strle...
    99+
    2023-06-20
  • C语言中的内联函数(inline)与宏定义(#define)详细解析
    先简明扼要,说下关键:1、内联函数在可读性方面与函数是相同的,而在编译时是将函数直接嵌入调用程序的主体,省去了调用/返回指令,这样在运行时速度更快。2、内联函数可以调试,而宏定义是不...
    99+
    2022-11-15
    内联函数 宏定义
  • C语言文件操作与相关函数介绍
    目录1.操作的准备2.文件的打开3.文件的使用方式4.相关的函数4.1 fputc4.2 fgetc4.3 fputs4.4 fgets4.5 fprintf4.6 fscanf4....
    99+
    2022-11-13
  • C语言rand和srand函数使用方法介绍
    目录前言随机数的本质重新播种生成一定范围内的随机数连续生成随机数前言 在实际编程中,我们经常需要生成随机数,例如,贪吃蛇游戏中在随机的位置出现食物,扑克牌游戏中随机发牌。 在C语言中...
    99+
    2023-02-11
    C语言rand和srand C语言rand方法 C语言srand方法
  • C语言简明介绍指针的使用
    目录1. 指针类型2. 野指针3. 指针的运算3.1 指针+-整数3.2指针-指针3.3 指针的关系运算4. 指针数组1. 指针类型 指针以字节为单位; 指针类型决定了解引用时能访问...
    99+
    2022-11-13
  • 用c语言编写一个幂函数(c语言实现幂函数)
    下面是一个使用C语言编写的幂函数的示例:```c#include double power(double base, int exp...
    99+
    2023-09-22
    c语言
  • C语言中qsort函数的介绍与用法实例
    目录一.qsort函数是什么 二.使用qsort排序-以升序为例1.整形数组排序2.字符数组排序3.字符指针数组排序4.结构体数组排序5.浮点型数组排序三.使用冒泡排序思想...
    99+
    2022-11-12
  • C语言函数栈帧的创建和销毁介绍
    在初学c语言中,很多时候要记的内容有点多,有时候并不能深入的了解它。关于函数的栈帧可以帮助我们深入了解函数传参的过程,让我们了解c语言。 以下是我们平时接触过,但不了解的问题: 1...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作