开门见山
offsetof
用于获取结构体成员的相对偏移,container_of
通过结构体字段获取结构体地址。
offsetof
offsetof
的标准实现如下,其被定义在stddef.h
中:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
offsetof
宏的计算发生在编译阶段。
GCC
编译器还为此提供一个内置函数__builtin_offsetof
以提高编译效率:
#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
container_of
#define container_of(ptr, type, member) ({
const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) );})
typeof
是GCC
编译器的一个扩展,用于获取变量或表达式的类型。在container_of
宏中,typeof( ((type *)0)->member )
用于获取结构体type
中成员member
的类型。
Linux
内核实现中,为了更严格的类型检查,和更好的符合C语言标准,container_of
宏的实现如下:
#define container_of(ptr, type, member) ({
void *__mptr = (void *)(ptr);
static_assert(__same_type(*(ptr), ((type *)0)->member) ||
__same_type(*(ptr), void),
"pointer type mismatch in container_of()");
((type *)(__mptr - offsetof(type, member))); })
static_assert
是C11
引入的静态断言机制,__same_type
由GCC
编译器提供的内置函数实现。
实际应用
container_of
典型的应用就是Linux
内核中链表的实现:
struct list_head {
struct list_head *next, *prev;
};
#define list_entry(ptr, type, member)
container_of(ptr, type, member)
// 通过链表节点获取节点所在结构,以下为示意,省略部分代码
struct my_struct {
int a;
char b;
struct list_head node;
};
struct my_struct data;
struct my_struct *entry = list_entry(&data, struct my_struct, node)
阅读全文