标准库中的 offsetof

在标准库 <stddef.h> 中,通常也定义了 offsetof 宏。传统的实现可能是这样的:

#define offsetof(type, member) ((size_t)&((type *)0)->member)

这个宏的工作原理是:

  1. 将 0 强制转换为 type * 类型的指针,即假设结构体的起始地址是 0
  2. 访问成员 member,此时 &((type *)0)->member 就是成员 member 的地址。
  3. 因为结构体的起始地址是 0,所以成员的地址就是它的偏移量。
  4. 最后将结果转换为 size_t 类型。

为什么用 __builtin_offsetof

使用 __builtin_offsetof 的好处是:

  1. 更安全:传统的 offsetof 实现依赖于对 0 地址的解引用,这在技术上是不合法的(尽管在实践中可以工作)。
  2. 更高效:编译器可以直接计算偏移量,而不需要生成实际的指针操作代码。
  3. 可移植性:__builtin_offsetof 是编译器内置的,可以正确处理各种复杂的结构体和平台相关的对齐问题。

offsetof 的用法

offsetof 的典型用法是计算结构体中成员的偏移量。例如:

#include <stddef.h>
#include <stdio.h>
 
struct example {
    int a;
    char b;
    double c;
};
 
int main() {
    printf("Offset of a: %zu\n", offsetof(struct example, a)); // 通常是 0
    printf("Offset of b: %zu\n", offsetof(struct example, b)); // 可能是 4(取决于对齐)
    printf("Offset of c: %zu\n", offsetof(struct example, c)); // 可能是 8
    return 0;
}