offsetof和container_of的介绍

offsetof

定义

//include/linux/stddef.h
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

目的
获得结构体(TYPE)的变量成员(MEMBER)在此结构体中的偏移量

用法

#include <stdio.h>

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

typedef struct test {
    int a;
    int b;
    int c;
    int d;
} test_t;

int main(int argc, char const *argv[])
{
    int a_offset = offsetof(test_t, a);
    int b_offset = offsetof(test_t, b);
    int c_offset = offsetof(test_t, c);
    int d_offset = offsetof(test_t, d);

    printf("a: %d, b: %d, c: %d, d: %d\n", a_offset, b_offset, c_offset, d_offset);

    return 0;
}

打印结果:
a: 0, b: 4, c: 8, d: 12

 

container_of

定义

#define BUILD_BUG_ON_MSG(cond, msg) (0) /* 无意义 */
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) /* 判断类型是否一致 */

//include/linux/kernel.h
#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))); })

目的
根据结构体(type)变量中的成员变量(member)的指针(ptr)来获取指向整个结构体变量的指针

用法

#include <stdio.h>

#define BUILD_BUG_ON_MSG(cond, msg) (0)

#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))

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

#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))); })

typedef struct test {
    int a;
    int b;
    int c;
    int d;
} test_t;

int main(int argc, char const *argv[])
{
    test_t t1;
    test_t *t2;

    t1.a = 1;
    t1.b = 2;
    t1.c = 3;
    t1.d = 4;

    t2 = container_of(&t1.a, test_t, a);
    printf("t2->a: %d, t2->b: %d, t2->c: %d, t2->d: %d\n", t2->a, t2->b, t2->c, t2->d);

    return 0;
}

打印结果:
t2->a: 1, t2->b: 2, t2->c: 3, t2->d: 4

应用

利用container_of构建一个结构体指针变量,并且将第一个参数的值赋值给结构体中对应的成员。

#include <stdio.h>

#define BUILD_BUG_ON_MSG(cond, msg) (0)

#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))

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

#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))); })

typedef struct test {
    int a;
    int b;
    int c;
    int d;
} test_t;

int main(int argc, char const *argv[]) {
    int value = 100;
    test_t* t1 = container_of(&value, test_t, a);
    printf("t1->a: %d\n", t1->a);

    test_t* t2 = container_of(&value, test_t, d);
    printf("t2->d: %d\n", t2->d);

    return 0;
}

打印结果:
t1->a: 100
t2->d: 99

释义

假设代码中value的地址是固定的,固定为0x0010

typedef struct test {
    int a;
    int b;
    int c;
    int d;
} test_t;

int main(int argc, char const *argv[]) {
    int value = 100;
    printf("addr value: %p\n", &value); /* 0x0002 */

    size_t a_offset = offsetof(test_t, a);
    size_t b_offset = offsetof(test_t, b);
    size_t c_offset = offsetof(test_t, c);
    size_t d_offset = offsetof(test_t, d);
    printf("a_offset: %ld\n", a_offset); /* 0 */
    printf("b_offset: %ld\n", b_offset); /* 4 */
    printf("c_offset: %ld\n", c_offset); /* 8 */
    printf("d_offset: %ld\n", d_offset); /* 12 */

    /* 1. 0x0010 - 0 = 0x0010
        2. 所以t的地址为 0x0010
        3. t->a的地址和t的地址是一致的,所以t->a的地址是 0x0010
        4. 0x0010 的地址中存放的数据为value = 100, 所以t->a的值为100
     */
    test_t* t = container_of(&value, test_t, a);

    /* 1. 0x0010 - 4 = 0x000C
        2. 所以t2的地址为 0x000C
        3. t2->b的地址是t2的地址偏移4,所以t2->b的地址是 0x0010
        4. 0x0010 的地址中存放的数据为value = 100, 所以t2->b的值为100
     */
    test_t* t2 = container_of(&value, test_t, b);

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值