跳转到内容

C 编程/stddef.h/函数参考

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


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(),它允许类似混合类型的东西找到包含它的结构体:[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 参考". MSDN. 检索于 2010-09-19.
  2. "GCC offsetof 参考". 自由软件基金会. 检索于 2010-09-19.
  3. Greg Kroah-Hartman (2003-06). "container_of()". Linux Journal. 检索于 2010-09-19. {{cite web}}: 请检查日期值:|date= (帮助)
华夏公益教科书