linux内核中的两个宏offsetof、container_of

本文深入解析了Linux内核中常用的两个宏定义:offsetof 和 container_of。通过对 offsetof 的工作原理及其实现细节的介绍,帮助读者理解如何计算结构体成员的偏移量。此外,文章还详细介绍了 container_of 的作用及其内部实现机制,展示了如何通过成员指针找回所属结构体。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

老生常谈的两个宏(Linux)

1、Linux内核中常用的两个宏定义 

 

 

2、offsetof原理剖析 

编译器做了什么?

     - offsetof用于计算TYPE结构体中MEMBER成员的偏移位置 

     - 编译器清楚的知道结构体成员变量的偏移位置

     - 通过结构体变量首地址偏移量定位成员变量

 

3、编程实验 

offsetof原理剖析     offsetof.c

#include <stdio.h>  
  
#ifndef offsetof  
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER)    //根本不会访问0地址处,只是做加法  
#endif  
  
  
struct ST  
{              //偏移位置
    int i;     // 0  
    int j;     // 4  
    char c;    // 8  
};  
  
void func(struct ST* pst)  
{  
    int* pi = &(pst->i);    // (unsigned int)&pst + 0 编译器的做法
    int* pj = &(pst->j);    // (unsigned int)&pst + 4  
    char* pc = &(pst->c);   // (unsigned int)&pst + 8 
                            //( size_t )&((TYPE*)0)->MEMBER
    
    printf("pst = %p\n", pst);  
    printf("pi = %p\n", pi);  
    printf("pj = %p\n", pj);  
    printf("pc = %p\n", pc);  
}  
  
int main()  
{  
    struct ST s = {0};  
  
    func(&s);  
    func(NULL);  
  
    printf("offset i: %d\n", offsetof(struct ST, i));  
    printf("offset j: %d\n", offsetof(struct ST, j));  
    printf("offset c: %d\n", offsetof(struct ST, c));  
  
    return 0;  
}  

                

 

4、container_of剖析

( { } ) 是何方神圣? 

         - ( { } )GNU C编译器的语法扩展 

         - ( { } ) 与逗号表达式类似,结果为最后—个语句的值

  

typeof是—个关键字吗? 

         - typeof是GNU C编译器的特有关键字 

         - typeof只在编译期生效,用于得到变量的类型

最后的原理 

                   container_of就是通过结构变量中一个成员的地址找到这个结构体变量的首地址

5、编程实验 

container_of原理剖析     container_of.c

#include <stdio.h>

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

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

/*改写container_of_new和container_of结果一致*/
#ifndef container_of_new
#define container_of_new(ptr, type, member) ((type*)((char*)(ptr) - offsetof(type, member)))
#endif


 /* const typeof(((type*)0)->member)* __mptr = (ptr)的意义:
  * 做类型检查,在编译期编译器已知道member类型,不会在运行期访问0地址
  */

struct ST
{
    int i;     // 0
    int j;     // 4
    char c;    // 8
};


int main()
{
    struct ST s = {0};
    char* pc = &s.c;

    int e = 0;
    int* pe = &e;

    //通过pc指针以及偏移量计算结构体变量s地址
    struct ST* pst = container_of(pc, struct ST, c); //warning: use of GNU statement expression extension

    printf("&s = %p\n", &s);
    printf("pst = %p\n", pst);

    return 0;
}

 

                        

 

6、小结 

            编译器清楚的知道结构体成员变量的偏移位置 

            ( { } )与逗号表达式类似,结果为最后—个语句的值 

            typeof只在编译期生效,用于得到变量的类型 

            container_of使用( { } ) 进行类型安全检查

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值