linux container_of宏

1 结构体

假如我们有一个结构体Student,其定义如下:

typedef struct student
{
        int id;
        char name[30];
        int math;
}Student;

通过Student stu定义stu变量后,我们可以通过stu.id或stu.name来获取stu的成员。但如果想反过来,通过stu.id或者stu.name来获取stu变量的起始地址好像就没那么简单了,linux中的container_of宏就是为解决此问题而生的。 

2 container_of

在linux中container_of宏定义如下:

/**
 * 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))); })

container_of宏的包含3个参数:ptr、type和member,分别说明如下:

ptr: 第三个参数member的地址,这里可以理解为&stu.id或&stu.name;

type: 包含ptr的结构体名称,这里可以理解为Student;

member: ptr在结构体中的成员名。

为便于理解,我们通过用程序代码模拟如下:

#include <stdio.h>
#include <string.h>

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

typedef struct student
{
        int id;
        char name[30];
        int math;
}Student;

int main()
{
        Student stu;
        Student *sptr = NULL;
        int *idPtr;
        char *namePtr;
        int *mathPtr;
        idPtr   = &stu.id;
        namePtr = (char*)&stu.name;
        mathPtr = &stu.math;
        printf("idPtr   = %p\n", idPtr);
        printf("namePtr = %p\n", namePtr);
        printf("mathPtr = %p\n", mathPtr);
        stu.id = 110;
        strcpy(stu.name,"guodegang");
        stu.math = 100;
        sptr = container_of(idPtr, Student,id);
        printf("container ptr = %p\n",sptr);
        sptr = container_of(namePtr, Student,name);
        printf("container ptr = %p\n",sptr);
        sptr = container_of(mathPtr, Student,math);
        printf("container ptr = %p\n",sptr);
        return 0;
}

运行结果:

idPtr   = 0x7ffc75765a70
namePtr = 0x7ffc75765a74
mathPtr = 0x7ffc75765a94
container ptr = 0x7ffc75765a70
container ptr = 0x7ffc75765a70
container ptr = 0x7ffc75765a70
idPtr实际就是stu变量的地址,namePtr对应的是stu.name地址,mathPtr对应的是stu.math地址。

后面通过idPtr、namePtr、mathPtr都可以成功取得stu变量的地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值