标准库中的 offsetof
在标准库 <stddef.h>
中,通常也定义了 offsetof
宏。传统的实现可能是这样的:
#define offsetof(type, member) ((size_t)&((type *)0)->member)
这个宏的工作原理是:
- 将
0
强制转换为type *
类型的指针,即假设结构体的起始地址是0
。 - 访问成员
member
,此时&((type *)0)->member
就是成员member
的地址。 - 因为结构体的起始地址是
0
,所以成员的地址就是它的偏移量。 - 最后将结果转换为
size_t
类型。
为什么用 __builtin_offsetof
?
使用 __builtin_offsetof
的好处是:
- 更安全:传统的
offsetof
实现依赖于对0
地址的解引用,这在技术上是不合法的(尽管在实践中可以工作)。 - 更高效:编译器可以直接计算偏移量,而不需要生成实际的指针操作代码。
- 可移植性:
__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;
}