Linux container_of宏详细剖析

简介: Linux container_of宏详细剖析

1 offsetof宏的原理以及作用

在使用container_of宏之前,我们先来了解下offsetof这个宏,它在Linux内核里的源码是这个样子:

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

1.1 offsetof宏的工作原理

虚拟一个TYPE类型的结构体变量,通过TYPE.MEMBER的方式来访问MEMBER成员,进而得到MEMBER成员相对于整个结构体首地址的偏移量。


这句话理解起来看似很抽象,&((TYPE *)0)->MEMBER相当于得到了成员的偏移减去0地址偏移,也就是结构体的首地址,进而就得到了该成员相当于整个结构体的偏移量,接下来写一个例子就明白了:

1.2 offsetof宏编程案例

#include <stdio.h>
#define offsetof(TYPE,MEMBER) ((int) &((TYPE *)0)->MEMBER)
#pragma pack(4)
struct ptr
{
  char a ;
  short b ;
  int  c ;
  double d ;
};
#pragma pack()
int main(void)
{
  struct ptr Pt ;
  printf("ptr:%d\n",sizeof(struct ptr));
  //相对地址偏移量
  int offset = offsetof(struct ptr,a);
  printf("offset:%d\n",offset);
  int offset1 = offsetof(struct ptr,b);
  printf("offset1:%d\n",offset1);
  int offset2 = offsetof(struct ptr,c);
  printf("offset2:%d\n",offset2);
  int offset3 = offsetof(struct ptr,d);
  printf("offset3:%d\n",offset3);
  return 0 ;
}

运行结果:

640.png

在案例中,我们以默认4字节对齐得到的4个结构体变量在结构体中的偏移,明白了offsetof宏如何使用,就解决了我们的大疑问了,我们来看看container_of宏怎么使用吧。

2 Linux container_of宏的原理以及作用

Linux中的container_of宏长如下这个样子,那它有什么作用呢?我们来详细剖析一下。

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

2.1 container_of宏的工作原理

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


接下来写一个关于container_of宏的编程案例:

2.2 container_of宏编程案例

#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);
    printf("a:%c\n",pt->a) ;
    printf("b:%d\n",pt->b) ;
    printf("c:%d\n",pt->c) ;
    printf("d:%.2lf\n",pt->d);
    return 0 ;
}

运行结果:

640.png

往期精彩

谈谈做产品、做项目以及标准化相关的话题

推荐一个非常好的项目管理工具

带串口屏显示的Bootloader

分享一个很好用的按键组件

目录
相关文章
|
4月前
|
Shell Linux 开发工具
在Linux中,当你需要给命令绑定⼀个宏或者按键的时候,应该怎么做呢?
在Linux中,当你需要给命令绑定⼀个宏或者按键的时候,应该怎么做呢?
|
5月前
|
Linux
Linux EXPORT_SYMBOL宏详解
Linux EXPORT_SYMBOL宏详解
41 4
|
6月前
|
Linux 编译器 C语言
Linux 中 EXPORT_SYMBOL宏详解
Linux 中 EXPORT_SYMBOL宏详解
|
7月前
|
Linux 编译器 C语言
Linux EXPORT_SYMBOL宏详解
Linux EXPORT_SYMBOL宏详解
Linux EXPORT_SYMBOL宏详解
|
7月前
|
Linux 编译器
一起来认识Linux中的 BUILD_BUG_ON 宏
一起来认识Linux中的 BUILD_BUG_ON 宏
Linux内核基础篇——container_of原理和实际应用
Linux内核基础篇——container_of原理和实际应用
|
存储 Linux C语言
Linux 内核常见的宏(1):offsetof 和 container_of分析
Linux 内核常见的宏(1):offsetof 和 container_of分析
222 0
Linux 内核常见的宏(1):offsetof 和 container_of分析
|
Linux C语言
介绍几种LINUX编程中非常实用的调试程序宏变量
介绍几种LINUX编程中非常实用的调试程序宏变量
|
Linux 容器
Linux内核中的常用宏container_of
/* linux-2.6.38.8/include/linux/compiler-gcc4.h */ #define __compiler_offsetof(a,b) __builtin_offsetof(a,b) /* linux-2.
937 0