31.offsetof宏与container_of宏


31.1.offsetof宏
(1)作用:用宏来计算结构体中某个元素和结构体首地址的偏移量(其本质是通过编译器来帮我们计算)。
(2)原理:我们虚拟1个type类型结构体变量,然后用type.member的方式来访问某个member元素,继而得到member相对于整个变量首地址的偏移量。
(3)学习思路:第1步先学会用offsetof宏;第2步再去理解这个宏的实现原理(见图1)。


31.2.container_of宏
(1)作用:知道某个结构体中某个元素的指针,反推整个结构体变量的指针,继而得到结构体中其它元素的指针。
(2)typeof关键字:typeof(a)即由变量a得到a的类型,typeof就是由变量名得到变量的数据类型。
(3)原理:先用typeof得到member元素的类型,然后通过该类型定义指向member元素的指针,然后用该指针减去该元素相对于整个结构体变量的偏移量(偏移量用offsetof宏得到)后得到整个结构体变量的首地址,再把该地址强制类型转换为type *即可。
(3)学习思路:第1步先学会用container_of宏;第2步再去理解这个宏的实现原理(见图2)。


31.3.学习指南和要求
(1)基本要求:必须要掌握这两个宏的使用,即知道这两个宏接收什么参数,返回什么值,会用这两个宏来写代码,看见代码中别人用这两个宏能理解什么意思。
(2)升级要求:能理解这两个宏的工作原理,能表述出来,有些面试笔试题会这么要求。
(3)高级要求:能自己写出这两个宏,不要着急,慢慢来。


这里写图片描述


这里写图片描述


31.struct_macro
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 项目:offsetof宏与container_of宏
 * 功能:演示offsetof宏与container_of宏的使用。
 */
#include <stdio.h>

// offsetof宏:返回MEMBER元素相对于整个TYPE类型结构体首地址的偏移量
// 参数:TYPE为某个结构体类型,MEMBER为TYPE类型结构体中的某个元素
#define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)

// container_of宏:返回整个结构体变量的指针
// 参数:ptr为指向结构体中member元素的指针,type为某个结构体类型,member为该结构体中的某个元素
#define container_of(ptr, type, member) ({          \
    const typeof(((type *)0)->member) * __mptr = (ptr); \
    (type *)((char *)__mptr - offsetof(type, member)); })

struct mystruct
{
    char a;         // 偏移量0
    int b;          // 偏移量4
    short c;        // 偏移量8 
};

int main(int argc, char **argv)
{
    // 手动计算偏移量,然后通过指针方式访问结构体元素
    struct mystruct s1 = 
    {
        .a = 'c',
        .b = 20,
        .c = 8,
    };
    char *p1 = (char *)&s1;
    int *p2 = (int *)((char *)&s1 + 4);
    short int *p3 = (short int *)((char *)&s1 + 8);
    // *p1 = c. *p2 = 20. *p3 = 8.
    printf("*p1 = %c. *p2 = %d. *p3 = %d.\n", *p1, *p2, *p3);

    // 使用offsetof宏
    // offsetof(struct mystruct, a) = 0.
    // (char *)&(s1.a) - (char *)&s1 = 0.
    printf("offsetof(struct mystruct, a) = %d.\n", offsetof(struct mystruct, a));
    printf("(char *)&(s1.a) - (char *)&s1 = %d.\n", (char *)&(s1.a) - (char *)&s1);
    // offsetof(struct mystruct, b) = 4.
    // (char *)&(s1.b) - (char *)&s1 = 4.
    printf("offsetof(struct mystruct, b) = %d.\n", offsetof(struct mystruct, b));
    printf("(char *)&(s1.b) - (char *)&s1 = %d.\n", (char *)&(s1.b) - (char *)&s1);
    // offsetof(struct mystruct, c) = 8.
    // (char *)&(s1.c) - (char *)&s1 = 8.
    printf("offsetof(struct mystruct, c) = %d.\n", offsetof(struct mystruct, c));
    printf("(char *)&(s1.c) - (char *)&s1 = %d.\n", (char *)&(s1.c) - (char *)&s1);

    // 使用container_ofstruct mystruct s2 = 
    {
        .a = 'd',
        .b = 30,
        .c = 5,
    };
    // pS = 0xbfcc8350. &s2 = 0xbfcc8350.
    struct mystruct *pS = container_of(&(s2.a), struct mystruct, a);
    printf("pS = %p. &s2 = %p.\n", pS, &s2);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值