typeof、offsetof、container_of的解释
链表是内核最经典的数据结构之一,说到链表就不得不提及内核最经典(没有之一)的宏container_of。
- #define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
这个宏乍一看有点瘆人,宏里面包含了两个关键字:typeof和offsetof:
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
创建一个类型为const typeof( ((type *)0)->member ) *,即
类型为type结构的member域所对应的对象类型的常指针__mptr,并用ptr初始化之,这样一来,__mptr就指向了某一个type的
member域。因为数据结构是顺序存储的,此时如果知道member在type结构中的相对偏移,那么用__mptr减去此偏移便是ptr所属的
type的地址,因此宏的第二条语句应运而生:
- (type *)( (char *)__mptr - offsetof(type,member) );})
另一个主角出场了---offsetof,返回一个数据域在它所属的数据结构中的相对偏移,单位是size_t,宏定义如下:
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
将地址0强制转换为type *,那么0指向某一个type类型的对象,也就是此type对象的地址,那么(TYPE *)0)->MEMBER就是type的member域,现在取址后&((TYPE *)0)->MEMBER 就
是member域的地址,因为type的地址为0,则member的地址实质上就是它相对于type地址的偏移。这里为什么可以这样实现而不会出错呢?有
两点原因,其一,地址0是在编译器编译时已经指定好了的,其二,这里全部都是取址操作,并没内存数据访问,因此不会存在非法访问内存的问题。
typeof、offsetof、container_of的解释的更多相关文章
- typeof, offsetof, container_of宏
container_of宏实现如下: #define container_of(ptr, type, member) ({ \ )->member ) *__mptr = (ptr); \ (t ...
- [dev]typeof, offsetof 和container_of
转一篇文章.写的比较好,浅显易懂,还画了图. https://www.cnblogs.com/idorax/p/6796897.html 概况一下: container_of用到了typeof和off ...
- typeof, offsetof 和container_of
要理解Linux中实现的双向循环链表("侵入式"链表),首先得弄明白宏container_of. 本文尝试从gcc的关键字typeof和宏offsetof入手,循序渐进地剖析宏co ...
- 各大互联网公司前端面试题(js)
对于巩固复习js更是大有裨益. 初级Javascript: 1.JavaScript是一门什么样的语言,它有哪些特点? 没有标准答案. 2.JavaScript的数据类型都有什么? 基本数据类型 ...
- 深入理解es6-Promise对象
前言 在之前翻博客时,看到promise,又重读了一边,突然发现理解很浅,记的笔记也不是很好理解,又重新学习promise,加深理解,学以致用 在promise出来之前,js常用解决异 ...
- c&c++中的宏
1 c&c++中的宏 do {...} while (0); offsetof & container_of 2 引用 [1] do {...} while (0) 在宏定义中的作用 ...
- what's the help of "unnecessary" pointer comparison
引述自http://c-programming.itags.org/q_c-programming-language_191518.html 源代码中的宏min中使用了 (void) (&_x ...
- 我的JavaScript笔记--数据类型,预编译,闭包
在我们js中存储数据的空间可以分为两种,堆内存和栈内存 堆内存:我们定义的那些引用数据类型的数据都会在堆内存中开辟空间. 栈内存:我们运行的js代码还有我们定义的基本数据类型,都直接在栈内存中存储 ...
- 如何区分null和undefined
null和undefined是两种数据类型, 如果硬要区分的话. null是一种类型, 赋值变量为null型. 未定义的变量, 即为undefined. var a = null a // null ...
随机推荐
- 用jquery或js实现三个div自动循环轮播
//3个div的统一class = 'div' var index =0; //3秒轮播一次 var timer = setInterval(function(){ index = (inde ...
- 学习记录013-NFS相关知识点
一.NFS相关知识点 1.NFS常用的路径/etc/exports NFS服务主配置文件,配置NFS具体共享服务的地点/usr/sbin/exportfs NFS服务的管理命令,exportfs -a ...
- JS引用类型之——RegExp
前言 之前小猪分享过关于正则表达式的一些内容,具体请看传送门,今天小猪来分享怎么在js中使用正则表达式. 定义 ECMAScript通过RegExp类型来支持正则表达式.使用下面类似Perl的语法,就 ...
- Ubuntu用户相关基本命令
Linux是一个用户权限管理得很严格的系统,Ubuntu作为最受欢迎的桌面发行版,提供了简单易用的图形界面工具来管理用户,但是命令行工具往往更强大,用得熟练的话效率会更高.用户管理命令常用的有如下几个 ...
- html标签marquee实现走马灯效果(文字浮动)
marquee标签实现文字或图片的移动效果 <marquee direction = "right">文字<marquee>
- S1 : 递归
递归函数是在一个函数通过名字调用自身的情况下构成的,如下所示 function f(num){ if(num<=1){ return 1; } else { return num*f(num-1 ...
- S1 : 传递参数
ECMAScript 中所有函数的参数都是按值传递的.也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样.基本类型值的传递如同基本类型变量的复制一样,而引用类型值的传 ...
- 二模 (9)day1
第一题: 题目大意: 给出一个n位01串,要么不动它,要么把它删掉一个字符,要么插入一个字符(0或1),要么把一个1变成0,.使得有1的位置号的总和是n+1的倍数,或者是0. 解题过程: 1.直接枚举 ...
- Noip2014 提高组 T2 联合权值 连通图+技巧
联合权值 描述 无向连通图 G 有 n 个点,n-1 条边.点从 1 到 n 依次编号,编号为 i 的点的权值为 WiWi, 每条边的长度均为 1.图上两点(u, v)的距离定义为 u 点到 v 点的 ...
- C语言:文件操作
以附加方式打开文件,输入数据,关闭文件. #include<stdio.h> #include<stdlib.h> int main() { FILE *fp = NULL; ...