offsetof宏:结构体成员相对结构体的偏移位置

container_of:根据结构体成员的地址来获取结构体的地址

offsetof 宏

原型:

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

(TYPE *)0非常巧妙,告诉编译器有一个指向结构体 TYPE 的指针,其地址是0,然后取该指针的 MEMBER 地址 &((TYPE *)0)->MEMBER,因为基址是0,所以这时获取到的 MEMBER 的地址就是相当于在结构体 TYPE 中的偏移量了。

Example:

#include <stdlib.h>
#include <stdio.h>
#include <stddef.h> struct TYPE{
int mem;
int member;
}; int main()
{
struct TYPE type;
printf("&type = %p\n", &type);
printf("&type.member = %p\n", &type.member);
printf("&((struct type *)0)->member = %lu\n", ((size_t)&((struct TYPE *)0)->member) );
printf("offsetof(struct TYPE member) = %zd\n", offsetof(struct TYPE, member));
return 0;
}
/*
result:
&type = 0x7ffc1104a110
&type.member = 0x7ffc1104a114
&((struct type *)0)->member = 4
offsetof(struct TYPE member) = 4
*/

container_of 宏

原型:linux-4.18.5

/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
void *__mptr = (void *)(ptr); \
BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) && \
!__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })

网上所见更多是底下这个版本:

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

第一部分:void *__mptr = (void *)(ptr); const typeof( ((type *)0)->member ) *__mptr = (ptr);

两个的差别在于 __mptr 的类型一个是 void * ,一个是 type *。

void * 较为容易理解,下面来看看 type *:

关于 typeof 关键字其作用是返回变量的类型,简单理解就是如下,详细可参见GCC typeof在kernel中的使用——C语言的“编译时多态”

int a;
typeof(a) b; //这等同于int b;
typeof(&a) c; //这等同于int* c;

因此const typeof( ((type *)0)->member ) *__mptr = (ptr); 的作用就是通过 typeof 获取结构体成员 member 的类型,然后定义一个这个类型的指针变量 __mptr 并将其赋值为 ptr。

第二部分:(type *)( (char *)__mptr - offsetof(type,member) ),通过offsetof宏计算出 member 在 type 中的偏移,然后用 member 的实际地址__mptr减去偏移,得到 type 的起始地址。从上面关于offsetof宏的 Example 也可以验证这一点:

&type.member = 0x7ffc1104a114 - &((struct type *)0)->member = 4 = &type = 0x7ffc1104a110

offsetof与container_of宏分析的更多相关文章

  1. 对offsetof、 container_of宏和结构体的理解

    offsetof 宏 #include<stdio.h> #define offsetoff(type, member)      ((int)&((type*)0)->me ...

  2. linux中offsetof与container_of宏定义

    linux内核中offsetof与container_of的宏定义 #define offsetof(TYPE, MEMBER)    ((size_t) &((TYPE *)0)->M ...

  3. (转)offsetof与container_of宏[总结]

    1.前言 今天在看代码时,遇到offsetof和container_of两个宏,觉得很有意思,功能很强大.offsetof是用来判断结构体中成员的偏移位置,container_of宏用来根据成员的地址 ...

  4. offsetof与container_of宏[总结]

    1.前言 今天在看代码时,遇到offsetof和container_of两个宏,觉得很有意思,功能很强大.offsetof是用来判断结构体中成员的偏移位置,container_of宏用来根据成员的地址 ...

  5. 【转】container_of宏 分析

    在学习Linux驱动的过程中,遇到一个宏叫做container_of.该宏定义在include/linux/kernel.h中,首先来贴出它的代码: /** * container_of - cast ...

  6. container_of宏

    title: container_of宏 date: 2019/7/24 15:49:26 toc: true --- container_of宏 解析 在linux链表结构中有这样一个宏,通过成员变 ...

  7. container_of宏定义分析---linux内核

    问题:如何通过结构中的某个变量获取结构本身的指针??? 关于container_of宏定义在[include/linux/kernel.h]中:/*_** container_of - cast a ...

  8. 内核中container_of宏的详细分析【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637597.html 内核中container_of宏的详细分析 16年2月28日09:00:37 内核中 ...

  9. linux内核container_of宏定义分析

    看见一个哥们分析container_of很好,转来留给自己看 一.#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMB ...

随机推荐

  1. mysql<七>

    -- ########## 01.集合逻辑 ########## -- MySQL中,只实现了一种集合逻辑:逻辑与,有两种用法:UNION 和 UNION ALL -- 临时表1 CREATE TAB ...

  2. 使用命令在navicat中创建数据库和用户

    一.用高权限账号登录,即创建连接 二.选择高权限用户右键,调出命令窗口 三.使用sql语句创建数据库 create database 数据库名 DEFAULT CHARACTER SET gbk CO ...

  3. 014:Django内置的URL转换器

    Django内置的URL转换器: 上节中我们说了URL中传参的情况,传递参数是通过 <> 尖括号来进行指定的.并且在传递参数的时候,可以指定这个参数的数据类型,比如文章的 id 都是 in ...

  4. linux常用的命令一:系统工作命令

    系统工作命令: 帮助命令:man -h \ man --help(tips:‘--’长格式后用完整的选项名称,‘-’短格式后用单个字母缩写) echo命令:格式:echo [字符串|$变量] date ...

  5. 2018山东省赛 G Game ( Nim博弈 && DP )

    题目链接 题意 : 给出 N 堆石子,每次可以选择一堆石子拿走任意颗石子,最后没有石子拿的人为败者.现在后手 Bob 可以在游戏开始前拿掉不超过 d 堆的整堆石子,现在问你有几种取走的组合使得 Bob ...

  6. [NOIP2017]注意点

    1.数据大却没开long long 导致的gg.2.文件读入时stdin打成stdout...3.桶维护数值,有负值要平移,且数值最好稍大(否则可能RE).4.很智障地打错变量.5.DP或其他涉及到转 ...

  7. BZOJ 5028 小z的加油站

    bzoj链接 Time limit 10000 ms Memory limit 262144 kB OS Linux 感想 树上动态gcd的第二题也好了. [x] BZOJ 2257 [JSOI200 ...

  8. 搭建一套简单的web服务器,记录实验过程

    搭建web服务器 一.实验内容: 实验要求: 1.完成一个简单的web服务器,web服务器从mysql里读取数据进行返回 2.Mysql需要有一个单独的数据盘,每个mysql虚拟机的磁盘挂载方式需要都 ...

  9. [CF1093G]Multidimensional Queries:线段树

    分析 非常有趣的一道题. 式子中的绝对值很难处理,但是我们发现: \[\sum_{i=1}^{k}|a_{x,i}-a_{y,i}|=\sum_{i=1}^{k}max(a_{x,i}-a_{y,i} ...

  10. android界面的滑动切换功能

    左右滑动切换是几乎所有应用中都会用到的功能.在这里将相关资源进行总结 (1)viewflipper结合手势检测进行左右滑动. http://www.cnblogs.com/hanyonglu/arch ...