跳转到内容

C 编程/stddef.h/offsetof

来自维基教科书,开放的书籍,开放的世界

C 的 offsetof() 宏是 ANSI C 库中的一个功能,它存在于stddef.h中。它计算给定成员在一个结构体或联合体类型中的偏移量(以字节为单位),表达式类型为size_t。该offsetof() 宏接受两个参数,第一个是结构体名称,第二个是结构体中成员的名称。它不能被描述为 C 原型。[1]

该宏的“传统”实现依赖于编译器对指针的处理并不特别挑剔;它通过指定一个从地址零开始的假设结构体来获取成员的偏移量

#define offsetof(st, m) \
     ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))

这是通过将空指针强制转换为指向结构体的指针来实现的st,获取结构体中成员m的地址,将该地址强制转换为字符指针,然后使用指针算术来减去结构体的基地址,所有这些都导致结构体开头和成员开头之间的字符位置(即字节)数量。

虽然这在许多编译器中都能正确工作,但根据 C 标准,它具有未定义的行为,因为它涉及空指针的解引用和违反别名规则的强制转换。如果其中一个参数拼写错误,它也会导致令人困惑的编译器诊断。现代编译器通常使用特殊形式定义宏,例如[2]

#define offsetof(st, m) __builtin_offsetof(st, m)

它在 C 中实现通用数据结构时很有用。例如,Linux 内核使用offsetof()来实现container_of(),它允许类似于 Mixin 类型的结构找到包含它的结构体:[3]

#define container_of(ptr, type, member) ({ \
                const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                (type *)( (char *)__mptr - offsetof(type,member) );})

此宏用于从指向嵌套元素的指针中检索包含结构体,例如此循环遍历my_struct对象的链表

struct my_struct {
  const char * name;
  struct list_node list;
};

extern struct list_node * list_next(struct list_node *);

struct list_node * iter = /* ... */
while (iter)
{
  struct my_struct * elem = container_of(iter, struct my_struct, list);
  printf("%s\n", elem->name);
  iter = list_next(&elem->list);
}

参考文献

[编辑 | 编辑源代码]
  1. "offsetof reference". MSDN. Retrieved 2010-09-19.
  2. "GCC offsetof reference". Free Software Foundation. Retrieved 2010-09-19.
  3. Greg Kroah-Hartman (2003-06). "container_of()". Linux Journal. Retrieved 2010-09-19. {{cite web}}: Check date values in: |date= (help)
华夏公益教科书