功能
通过结构体成员变量
的地址获取其结构体变量(container)
的地址。
- 第一个参数
ptr
是成员的地址 - 第二个参数
type
是container的类型 - 第三个参数
member
是成员在container中的名称 - 返回的是container的地址
定义
// linux-3.10/include/linux/kernel.h
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
例子
#include <stdlib.h>
#include <stdio.h>
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
struct node_t {
struct node_t *next;
};
struct my_struct {
int a;
char b;
struct node_t c;
};
int main(){
struct my_struct m;
struct my_struct m2;
struct my_struct *pm2;
int * pa = &m.a;
char * pb = &m.b;
struct node_t * pc = &m.c;
void *ptr;
ptr = container_of(pc, struct my_struct, c);
printf("&m: %p, ptr: %p\n", &m, ptr);
ptr = NULL;
ptr = container_of(pa, struct my_struct, a);
printf("&m: %p, ptr: %p\n", &m, ptr);
ptr = NULL;
ptr = container_of(pb, struct my_struct, b);
printf("&m: %p, ptr: %p\n", &m, ptr);
m.c.next = &m2.c;
pm2 = container_of(m.c.next, struct my_struct, c);
printf("&m2: %p, pm2: %p\n", &m2, pm2);
return 0;
}
&m: 0x7ffe4c4393d0, ptr: 0x7ffe4c4393d0
&m: 0x7ffe4c4393d0, ptr: 0x7ffe4c4393d0
&m: 0x7ffe4c4393d0, ptr: 0x7ffe4c4393d0
&m2: 0x7ffe4c4393c0, pm2: 0x7ffe4c4393c0
简单解释
1.计算结构体成员相对 container 的偏移
2.用当前成员的地址减去偏移得到container结构体的地址
第一步的实现
(size_t) &((TYPE *)0)->MEMBER
#include <stdlib.h>
#include <stdio.h>
struct node_t {
struct node_t *next;
};
struct my_struct {
int a;
char b;
struct node_t c;
};
int main(){
struct my_struct m;
printf("&m: %p\n", &m);
printf("&m.a: %p\n", &m.a);
printf("&m.b: %p\n", &m.b);
printf("&m.c: %p\n", &m.c);
printf("%lu\n", (size_t) & ((struct my_struct *)0)->a);
printf("%lu\n", (size_t) & ((struct my_struct *)0)->b);
printf("%lu\n", (size_t) & ((struct my_struct *)0)->c);
return 0;
}
&m: 0x7ffd2af67fd0
&m.a: 0x7ffd2af67fd0
&m.b: 0x7ffd2af67fd4
&m.c: 0x7ffd2af67fd8
0
4
8
第二步的实现
const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) )
#include <stdlib.h>
#include <stdio.h>
struct node_t {
struct node_t *next;
};
struct my_struct {
int a;
char b;
struct node_t c;
};
int main(){
struct my_struct m;
struct my_struct *pm;
size_t offsetof_c = (size_t) & ((struct my_struct *)0)->c;
printf("offsetof_c: %lu\n", offsetof_c);
typeof(((struct my_struct *)0)-> c) *__mptr = &m.c;
printf("__mptr: %p\n", __mptr);
pm = (struct my_struct *)( (char *)__mptr - offsetof_c);
printf("&m: %p, pm: %p\n", &m, pm);
return 0;
}
offsetof_c: 8
__mptr: 0x7ffcc562a9c8
&m: 0x7ffcc562a9c0, pm: 0x7ffcc562a9c0
常见应用
// include/linux/rbtree.h
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
// include/linux/vmalloc.h
struct vmap_area {
unsigned long va_start;
unsigned long va_end;
unsigned long flags;
struct rb_node rb_node; /* address sorted rbtree */
// ...
};
// mm/vmalloc.c
static struct vmap_area *__find_vmap_area(unsigned long addr)
{
struct rb_node *n = vmap_area_root.rb_node;
while (n) {
struct vmap_area *va;
...
va = rb_entry(n, struct vmap_area, rb_node);
...
}
...
}
// include/linux/list.h
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
// include/linux/types.h
struct list_head {
struct list_head *next, *prev;
};
// include/linux/vmalloc.h
struct vmap_area {
...
struct list_head list; /* address sorted list */
...
};
// mm/vmalloc.c
static void *s_next(struct seq_file *m, void *p, loff_t *pos)
{
struct vmap_area *va = p, *next;
++*pos;
next = list_entry(va->list.next, typeof(*va), list);
...
return NULL;
}
网友评论