linux:内核container_of的使用
一、在linux 内核中,container_of 函数使用非常广,例如 linux内核链表 list_head、工作队列work_struct中。其实它的语法很简单,只是一些指针的灵活应用,它分两步:
第一步,首先定义一个临时的数据类型(通过typeof( ((type *)0)->member )获得)与ptr相同的指针变量__mptr,然后用它来保存ptr的值。
第二步,用(char *)__mptr减去member在结构体中的偏移量,得到的值就是整个结构体变量的首地址(整个宏的返回值就是这个首地址)。
需要注意的是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)); })
二、说简单一点就是container_of()的作用就是通过一个结构变量中一个成员的地址找到这个结构体变量的首地址。
三、实际测试。
1、测试代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.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) );})
struct test
{
int i;
int j;
char k;
};
typedef struct frame {
int a;
char b;
struct test temp;
char name[10];
} frame_t;
int main(int argc, char **argv)
{
frame_t fra, *pf,*pt;
struct test *mtest;
fra.a = 1;
fra.b = 2;
fra.temp.k=85;
snprintf(fra.name, 5, "wfh%d", 1);
pf=container_of(fra.name, frame_t, name);
printf("fra.a = %d, fra.b = %d, fra.name = %s\n", fra.a, fra.b, fra.name);
printf("pf.a = %d, pf.b = %d, pf.name = %s\n", pf->a, pf->b, pf->name);
mtest=container_of(&pf->temp.k,struct test, k);
printf("mtest->k = %d \n",mtest->k);
pt=container_of(mtest, struct frame, temp);
printf("pt.a = %d, pt.b = %d, pt.name = %s pt->temp.k=%d \n", pt->a, pt->b, pt->name,pt->temp.k);
return 0;
}
2、测试结果
$ gcc -o container_of container_of.c
$ ./container_of
fra.a = 1, fra.b = 2, fra.name = wfh1
pf.a = 1, pf.b = 2, pf.name = wfh1
mtest->k = 85
pt.a = 1, pt.b = 2, pt.name = wfh1 pt->temp.k=85
$