一、源码
#
1// include/linux/kernel.h
2
3/**
4 * container_of - cast a member of a structure out to the containing structure
5 * @ptr: the pointer to the member.
6 * @type: the type of the container struct this is embedded in.
7 * @member: the name of the member within the struct.
8 *
9 */
10#define container_of(ptr, type, member) ({ \
11 void *__mptr = (void *)(ptr); \
12 BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) && \
13 !__same_type(*(ptr), void), \
14 "pointer type mismatch in container_of()"); \
15 ((type *)(__mptr - offsetof(type, member))); })
二、分析
#
- 这个东西看了好久才看懂,不过真的很强大
- 考虑一个场景,我们定义树需要怎么写,类似下面这样
1struct treeNode {
2 treeNode *left;
3 treeNode *right;
4 void *value;
5};
- 这时发现这个value每次都要定义,并且每个treeNode都需要新建地址
- linux的这群大佬就开始搞事情,如果treeNode的地址和value的地址结合一下,不用每次创建两个地址,一个地址搞定
- 这时候就出现一种定义方式
1struct treeNode {
2 treeNode *left;
3 treeNode *right;
4};
5
6struct valueTemplate {
7 treeNode node;
8 int value;
9}
- 这样写,对树操作时不用关心value是啥,只需要关心自己的数据结构实现就好了
- 但是怎么找到value呢,
container_of
就出现了
1#define container_of(ptr, type, member) \
2 (type *)((char *)(ptr) - (char *) &((type *)0)->member)
3
4// 示例用法
5void func(treeNode *node) {
6 valueTemplate *value = container_of(node, struct valueTemplate, node)
7}
1valueTemplate *value = (valueTemplate *)((char *)node - (char *)&((valueTemplate *)0)->node)
- 加地址是向后偏移,减地址是向前偏移,所以这句话意思是通过成员变量找到结构体指针
- 使用0地址的成员变量的地址偏移来计算结构体指针到成员变量的偏移量,然后用成员变量地址向前偏移去查找value
- 这个想法是真的强大