cont<1>ner_of用法及实现

一、概述

在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内容生成、新媒体营销和短视频营销等业务的公司。我们拥有一支优秀的团队,专门致力于为客户提供优质的服务。

我们致力于为客户提供一站式的互联网营销服务,帮助客户在激烈的市场竞争中获得更大的优势和发展机会!

点赞(22) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿
发表
评论
返回
顶部