一、概述
在Linux内核中,经常会用到宏container_of,该宏的功能是通过某个结构体中的某个成员的地址,反推出该结构体的首地址。宏的定义如下:
```c
#define container_of(ptr, type, member) \
((type *)((char *)(ptr) - offsetof(type, member)))
```
其中,三个参数的含义分别是:
- ptr:一个指向某个类型指针的指针。
- type:要求得到的结构体的类型。
- member:type结构体中,要求求出的变量的名称。
接下来,我们将结合示例,介绍container_of的用法及实现原理。
二、使用方法
下面是一个示例代码,用于演示如何使用container_of:
```c
#include #include #include struct person{ char *name; int age; struct list_head list; }; struct list_head{ struct list_head *prev,*next; }; #define offsetof(TYPE,MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr,type,member) \ ((type *)((char *)(ptr) - offsetof(type,member))) int main(void) { struct person p; struct list_head *pos; p.name = "Jack"; p.age = 22; pos = &(p.list); struct person *ptr = container_of(pos,struct person,list); printf("name: %s, age: %d\n",ptr->name,ptr->age); return 0; } ``` 在这个示例代码中,我们定义了一个结构体person,其中包含名字、年龄和一个指向list_head类型的指针。list_head是一个链表的节点,每个链表节点包括前驱指针prev和后继指针next。另外,我们还定义了宏offsetof和container_of,用于求结构体成员的偏移量以及从链表节点指针计算出person结构体地址的宏。 在main函数中,我们创建了一个person结构体,将其地址赋值给一个list_head类型的指针pos。然后,使用container_of宏求出person结构体的地址,最后打印出person结构体中的信息。 三、实现原理 container_of的实现原理并不复杂。在本例中,container_of的实现如下所示: ```c #define container_of(ptr,type,member) \ ((type *)((char *)(ptr) - offsetof(type,member))) ``` 其中,offsetof是一个C库函数,用于求结构体成员的偏移量。例如,要求出person结构体中,list成员偏移量的代码如下: ```c size_t offset = offsetof(struct person,list); ``` 在这个例子中,offset的值是0。 container_of的实现原理是先将ptr转换成char *类型,然后减去list成员在person结构体中的偏移量,得到person结构体的首地址。最后将指针强制转换成type*类型即可。 接下来,我们来具体解释上述代码的实现: ```c ((char *)(ptr) - offsetof(type,member)) ``` 该代码将指针ptr强制转换成char*类型,并减去member成员在type结构体中的偏移量。由于ptr本来就是指向一个类型指针的指针,所以ptr本身所指向的内存区域,其实包含了一个指向type类型的指针和该type类型变量的其它成员。因此,将ptr转换成char*类型,是为了让compiler认为ptr所指向的内存区域是一个连续的内存区域。 例如,在这个例子中,ptr指向person结构体中的list成员,在内存中,其实包括了指向person类型的指针、name成员和age成员: ``` | --> pointer to struct person | | | | +------------+ | | | name member| | | +------------+ | | | age member | | | +------------+ | | list member | pointer to struct list_head | ``` 由于compiler是知道person结构体中list成员的偏移量的,因此可以通过char*类型的指针,很方便地计算出person结构体首地址: ```c ((char *)(ptr) - offsetof(type,member)) ``` 最后,将char*类型的指针强制转换成type*类型,就可以得到person结构体的首地址了。 最后,总结一下本文介绍的container_of用法及实现原理。container_of宏的主要作用是给定一个指向结构体成员变量的指针,然后反推出该结构体变量的首地址。container_of的实现方法是通过结构体成员在该结构体中的偏移量,加上指向结构体成员变量的指针,得到该结构体变量的首地址。在实现过程中,使用了C语言库函数offsetof以及char*类型指针的计算方法。 壹涵网络我们是一家专注于网站建设、企业营销、网站关键词排名、AI内容生成、新媒体营销和短视频营销等业务的公司。我们拥有一支优秀的团队,专门致力于为客户提供优质的服务。 我们致力于为客户提供一站式的互联网营销服务,帮助客户在激烈的市场竞争中获得更大的优势和发展机会!
发表评论 取消回复