🔥博客主页:PannLZ
🎋系列专栏:《Linux系统之路》
container_of宏
假设有一个struct person,其定义如下:
struct person {
int age;
char *name;
} p;
只用age或name上的指针就可以检索包装(包含)该指针的整个结构。顾名思义,container_of宏用于查找指定结构字段的容器。该宏在
include/linux/kernel.h
中定义,如下所示:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
看起来好复杂,慢慢分析。
ptr是成员变量的指针, type是指结构体的类型, member是成员变量的名字。
typeof:
typeof,是用于返回一个变量的类型,这是GCC编译器的一个扩展功能
(((type *)0)->member):
((TYPE *)0)
将0转换为type类型的结构体指针,换句话说就是让编译器认为这个结构体是开始于程序段起始位置0,开始于0地址的话,我们得到的成员变量的地址就直接等于成员变量的偏移地址了。 (((type *)0)->member)
引用结构体中member成员。
//示例
typedef struct student{
int id;
char name[30];
int math;
}Student;
int main()
{
//这里时把结构体强制转换成0地址,然后打印name的地址。
printf("%d\r\n",&((Student *)0)->name);//4
return 0;
}
const typeof(((type )0)->member)__mptr = (ptr);
这句代码意思是用typeof()获取结构体里member成员属性的类型,然后定义一个该类型的指针变量mptr,并将ptr所指向的member的地址赋给mptr;
offsetof(type, member))
((size_t) &((TYPE*)0)->MEMBER)
//size_t是一个非负数,所以size_t通常用来计数
((size_t) &((TYPE*)0)->MEMBER)
结合之前的解释,我们可以知道这句话的意思就是求出MEMBER
相对于0地址的一个偏移值。
(type *)((char *)__mptr - offsetof(type, member))
这句话的意思就是,把 __mptr 转换成 char * 类型, 因为 offsetof 得到的偏移量是以字节为单位。 两者相减得到结构体的起始位置, 再强制转换成 type(该结构的) 类型。
也可以把它简单看为:
container_of(pointer, container_type,container_field);
- pointer:指向结构字段的指针。
- container_type:包装(包含)指针的结构类型。
- container_field:pointer指向的结构内字段的名称。
通过一个例子来认识它的功能:
struct person somebody;
[...]
char *the_name_ptr = somebody.name;
struct person *the_person;
the_person = container_of(the_name_ptr, struct person, name);
//通过指向person结构的name成员的指针(地址),来获取指向struct结构体起始地址的指针
//驱动开发中的例子:
struct mcp23016 {
struct i2c_client *client;
struct gpio_chip chip;
}
/* 检索给定指针chip字段的mcp23016结构体*/
static inline struct mcp23016 *to_mcp23016(struct gpio_chip *gc)
{
return container_of(gc, struct mcp23016,chip);
}
static int mcp23016_probe(struct i2c_client* client,const struct i2c_device_id *id)
{
struct mcp23016 *mcp;
[...]
mcp = devm_kzalloc(&client->dev,sizeof(*mcp), GFP_KERNEL);
if (!mcp)
return -ENOMEM;
[...]
}
参考文章:
1.https://blog.csdn.net/qq_33475105/article/details/119301916
2.https://radek.io/2012/11/10/magical-container_of-macro/