关于linux kernel中的container_of宏的困惑

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

最近在看linux kernel中的链表操作, 看到了如上这个宏, 其实表达的意思很简单, 但是他要用一个__mptr来指向ptr甚是不解?实测如下宏也是可行的:
#define container_of(ptr, type, member) ({ \
(type *)( (char *)ptr - offsetof(type,member) );})

内核用一个临时const变量来存储ptr是为什么啊? 并且第一步还要强行获得ptr的对象类型, 第二步又将mptr强转成char *类型, 就我目前的知识来看这种操作好鸡肋, 内核这样做是适应编译器的操作“习惯”吗? 还是说有其它的“难言之隐“?有大神能帮忙解答一下吗? 
0

1个回答

GNU C把包含在括号里的复合语句看做是一个表达式,称为语句表达式,它可以出现在任何允许表达式的地方。我们可以在语句表达式中使用原本只能在复合语句中使用的循环变量、局部变量等

例如int aa = ({3; 43-5;});使用不支持GNU C的编译器会报错,而使用gcc会得到aa为38
利用GNU C的这种特性,我们可以避免一些宏定义产生副作用,如使用

#define min_t(type,x,y) \
({type x=(x); type __y=(y);x<__y?__x:__y})
代替

#define min(x,y) ((x)<(y)?(x):(y))
可避免传入min(a++,b++)产生副作用

所以, const typeof( ((type *)0)->member ) *__mptr = (ptr);是为了确保不会得到任何ptr表达式,都不会有副作用。

1
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
最详尽解释Linux内核源码中的container_of宏及其标准C版本实现
在Linux内核源码文件 include/linux/kernel.h中,定义了container_of宏,源码如下:/** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type:
linux 内核中的container_of()如何使用
一、如何使用 我们先来分析一下container_of(ptr,type,member),这里面有ptr,type,member分别代表指针、类型、成员。看一个例子: struct test         {                 int i;                 int j;                 char k;         };
Linux字符驱动中container_of宏的作用
首先看看这个宏的原型:     container_of(ptr,type,member)    功能:根据一个结构体变量中的一个成员变量的指针来获取指向整个结构体变量的指针。     参数:          ptr:已知的结构体成员的首地址(指针);          type:要获取的结构体变量的类型          member:要获取的结构体变量中成员的名字,而不是类型
Linux内核中的container_of函数简要介绍
container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址。container_of的定义如下: #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)-&amp;gt;member ) *__...
Linux内核之container_of详细解析
container_of用来根据成员变量查找所在基结构体的地址,其宏定义如下:#define container_of(ptr, type, member) ({                      \        const typeof( ((type *)0)-&amp;gt;member ) *__mptr = (ptr);    \        (type *)( (char *)__...
c++11下 container_of编译不通过
gcc main.cpp -o main -std=c++11 报错如下:   原因:需要支持gnu++11扩展 gcc main.cpp -o main -std=gnu++11   编译通过
linux kernel list的应用
基于利用linux kernel的list.h的宏操作,写的一些例子,对理解container_of ,list操作有帮助
linux驱动开发之字符设备--私有数据和container_of
前言 驱动开发中通常为设备定义一个设备相关的设备结构体,其包含该设备的cdev 、私有数据、信号量、irq等这些信息。 驱动开发中通常将文件的私有数据private_data指向设备结构体,在read()、write()、ioctl()等函数通过 private_data 访问数据 设备结构体。 container_of() 是一个比较常用的宏,其作用为通过结构体成员的指针找到对应结构体
kernel 增加自定义宏编译开关
在MAKEFILE适当位置增加如下定义: LINUXINCLUDE    := \ -I$(srctree)/arch/$(hdr-arch)/include \ -Iarch/$(hdr-arch)/include/generated \ $(if $(KBUILD_SRC), -I$(srctree)/include) \ -Iinclude \ $(USERINCLUDE)
如何在Linux kernel Makefile中添加宏定义
原文地址:http://freshpassport.blog.51cto.com/2359526/619274 如何在Linux kernel Makefile中添加宏定义:   CFLAGS_object.o += -DMACRO_NAME 在编译object.o时定义宏MACRO_NAME,在kernel中添加自己的模块时比较有用。   另外,要想对所以将编译的文件都添加一
linux 进程调度switch_to宏浅析+系统执行过程总结
switch_to宏调试
kernel中__init等宏总结
关于__init、__initdata、__exit、__exitdata及类似的宏打开Linux Kernel源代码树中的文件:include/init.h,可以看到有下面的宏定议:#define __init __attribute__ ((__section__ (".init.text"))) __cold #define __initdata __attribute__ (( _
Linux内核 __setup宏分析
在解析cmdline时,我们经常会使用到__setup宏,用来处理kernel的cmdline。 #define __setup(str, fn) \ __setup_param(str, fn, fn, 0) #define __setup_param(str, unique_id, fn, early) \ static char __setup_str_##unique_id[] __in...
linux 内核常用数据结构及算法——container_of
container_of是linux内核中常用的一个宏函数,其用途是通过结构体一个yu
kernel常用函数、宏、结构体
1 __setup 2 early_param 3 MACHINE_START 4 __attribute__编译属性 section 4.1 initcall宏定义 5 current 6 关于打开设备结点(struct inode和struct file) 7 struct page 8 struct mm_struct 9 struct task_struct 1...
linux——内核中container_of宏
前言 在查看linux内核中,经常会看到container_of这个宏定义,第一眼看到这个宏定义中括号一层又一层,晕了。下面本文就来好好分析这个宏的具体实现。 内核版本:linux-2.6.34 container_of宏详解 container_of宏的源码定义在kernel.h文件中,具体如下: /** * container_of - cast a member of a...
Linux内核源码中使用宏定义的若干技巧
在C中,宏定义的概念虽然简单,但是真要用好却并不那么容易,下面从Linux源码中抽取一些宏定义的使用方法,希望能从中得到点启发: 1. 类型检查 比如module_init的宏定义: 点击(此处)折叠或打开 #define module_init(initfn)                    \     static inline in
linux内核中的likely()和unlikely()宏的作用
在看linux内核代码的时候,经常会看到likely(x)和unlikely(x)宏的使用。那这两个宏有什么作用呢? 这两个宏在内核中的定义如下: # define likely(x) __builtin_expect(!!(x), 1) # define unlikely(x) __builtin_expect(!!(x), 0) 可见这里使用了gcc的内建函数__builtin_exp
C语言小结--offsetof和container_of宏的使用
在Linux内核中这两个宏的使用非常普遍,所以研究透彻这两个宏非常有必要。接下来详细介绍一下这两个宏的使用。 1、offsetof宏的使用 这个宏比较简单,其作用就是求一个结构体成员变量在这个结构体中的偏移量。在Linux kernel中的路径是:include/linux/stddef.h 我们先来看一下这个宏的原型: #define offsetof(TYPE, MEMBER) ((
container_of宏实现原理
1、在内核中的原型: #define container_of(ptr, type, member) ({            \        const typeof(((type *)0)-&amp;gt;member) * __mptr = (ptr);    \        (type *)((char *)__mptr - offsetof(type, member)); }) #end...
Linux内核导出符号宏定义EXPORT_SYMBOL的源码分析
源代码: ……. #ifndef MODULE_SYMBOL_PREFIX #define MODULE_SYMBOL_PREFIX "" #endif ……. struct kernel_symbol      //内核符号结构 {        unsignedlong value;  //该符号在内存地址中的地址        constchar *name;    /
从一个简单的宏定义看linux内核的严谨
最近闲来无事,分析下linux kernel里面一些函数都是怎样定义使用的,它们都是怎样避免风险的,从include/linux/kernel.h中挑出一个经典的min宏进行分析一下   从我们最先认识的min函数开始看看,这个函数的作用就是求两个数中小一点的那个 #define min(x, y) ({                                \ typeof(x)
Linux 内核基础--rb_tree使用方法
1.在你的所要使用的模块中包含头文件#include<linux/rb_tree.h>2.将rb_node嵌入到自己结构体中struct my_data{ struct rb_node node; char key[32]; char value[32] };3.定义rb树的根,一般为全局变量struct rb_root my_root_tree = RB_ROOT;4.实现
linux内核之container_of()详解(即:list_entry()的详解)
#define list_entry(ptr, type, member) ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) 减号右边分析:(unsigned long)(&((type*)0)->member) (type*)0: 把0地址强制转换成type结构体的地址,表示0地址处存放了type类型的结构体变量,为什么在0处强转为结构体地址,这也是个设计巧妙点;((type*)0)->member:这个表示指向结构体
linux内核里面几个特殊的宏定义
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
学习上的困惑
1.之前在纠结到底要用哪种语言去学数据结构和算法:用python,更快熟悉python,用c,看得懂别人的代码也是一种学习,没有python那么快,鉴于自己想学习AI...
linux内核红黑树运用小实例
linux内核版本linux-3.10.36 结构 linux内核的rb_node结构体 struct rb_node { unsigned long __rb_parent_color; struct rb_node *rb_right; struct rb_node *rb_left; } __attribute__((aligned(sizeof(long
HZ、CONFIG_HZ 和 jiffies 变量在 linux内核源码中定义的位置
HZ  和 CONFIG_HZ 宏定义的位置: 实际上在 linux-2.6.x/include/asm/param.h  定义了HZ的值:   /*  *  arch/arm/include/asm/param.h  *  *  Copyright (C) 1995-1999 Russell King  *  * This program is free softwa
分析内核中的current宏,并自己实现
说明:   current宏,是一个全局指针,指向当前进程的struct task_struct结构体,即表示当前进程。   例如current->pid就能得到当前进程的pid,current-comm就能得到当前进程的名称。   每个进程会有两个栈,一个用户栈,存在于用户空间,一个内核栈,存在于内核空间。   当进程在用户空间运行时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用
Linux内核常见宏的作用
__init 位置: /include/linux/init.h 定义: #define __init __attribute__ ((__section__ (&amp;quot;.init.text&amp;quot;))) 注释:这个标志符和函数声明放在一起,表示gcc编译器在编译时,需要把这个函数放在.text.init Section 中,而这个Section 在内核完成初始化之后,就会被释放掉。 举例: as...
Linux内核--各种宏定义
1. asmlinkage宏 [cpp] view plain copy #define asmlinkage __attribute__((regparm(0))).    解释:gcc编译器在汇编过程中调用c语言函数时传递参数有两种方法:一种是通过堆栈,另一种是通过寄存器。缺省时采用寄存器,假如你要在你的汇编过程中调用c语言函数,并且想通过
【总结】Linux内核中CONFIG_OF宏的解释
转自 https://blog.csdn.net/manderen/article/details/55260817 关于Linux内核中CONFIG_OF宏,OF是Open Firmware的缩写。 Open Firmware. This was invented long time ago when Apple was producing laptops based on PowerPC ...
container_of注意事项
已知一个变量的地址时,使用container_of获取此变量所在的结构体的首指针。其定义如下: #define container_of(ptr, type, member) ({              \     void *__mptr = (void *)(ptr);                   \     BUILD_BUG_ON_MSG(!__same_type(*(ptr...
关于container_of宏的疑问
linux/kernel.h中的定义:rn#define container_of(ptr, type, member) ( \rn const (typeof(((type *)0)->member) *)__mptr = ptr; \rn (type *)(__mptr - offsetof(type, member)); \rn)rnrn为何不能定义成这样,而非要用一个局部变量来保存ptr,有什么好处?rn#define container_of(ptr, type, member) ( \rn (type *)(ptr - offsetof(type, member)); \rn)
【Linux】Linux基础知识(Linux系统、Linux中的链表)
Linux系统简介 Linux系统的结构及特点 Linux系统的结构图如下图所示: 从上图可以看出,Linux是一个典型的宏内核(一体化内核)结构。硬件系统上面时硬件抽象层,在硬件抽象层上面时内核服务功能模块,这些模块通过系统调用接口向用户进程提供服务。 Linux进程管理的系统调用包括:进程的创建、调度、中止、等待等。 Linux支持内存管理控制器MMU,使用虚拟内存管理机制。虚拟...
linux内核源码中常见宏定义
1. gcc的__attribute__编绎属性要了解Linux Kernel代码的分段信息,需要了解一下gcc的__attribute__的编绎属性,__attribute__主要用于改变所声明或定义的函数或数据的特性,它有很多子项,用于改变作用对象的特性。比如对函数,noline将禁止进行内联扩展、noreturn表示没有返回值、pure表明函数除返回值外,不会通过其它(如全局变量、指针)
makefile 中定义宏位置需要注意一下
1 CUR_DIR = $(shell pwd) 2 3 CFLAGS = -g -Wall 4 GCC = gcc 5 GXX = g++ 6 7 TARGET = exe.out 8 9 SRC_FILES += $(shell find $(CUR_DIR) -name *.cc) \ 10 += $(shell find $(CU
Linux内核的WRITE_ONCE函数分析
Linux kernel中list.h中 链表的初始化函数如下static inline void INIT_LIST_HEAD(struct list_head *list){    WRITE_ONCE(list-&amp;gt;next, list);    list-&amp;gt;prev = list;}上面一段代码的作用是初始化链表,使前向指针和后向指针分别指向list自己。不理解WRITE_ONC...
宏container_of
LDD3的代码:rnstruct scull_dev *dev;rndev = container_of(inode->i_cdev, struct scull_dev, cdev);rnfilp->private_data = dev;rnrn按宏container_of的定义,第一个参数应该是指向结构实例某成员的指针,但这里的inode->i_cdev却是kdev_t结构,而不是cdev结构。哪位兄弟能帮解释下,万分感激!
老生常谈的Linux内核中常用的两个宏定义
1. 第一个宏:offsetof用于计算 TYPE 结构体中 MEMBER 成员的偏移位置 #ifndef offsetof #define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER) #endif 仔细一看,编译器到底做了什么? size_t类型就是long unsigned int类型,这句代码的意思不就是C语言里面的强制类型
文章热词 设计制作学习 机器学习教程 Objective-C培训 交互设计视频教程 颜色模型
相关热词 mysql关联查询两次本表 native底部 react extjs glyph 图标 java中关于线程的学习 数据库中关于课程的表