今儿个,咱来聊聊C语言里头一个挺有意思的玩意儿——offsetof
。这东西干啥用的?说白,就是能告诉你,一个结构体里头,某个成员它搁哪儿,离结构体的老窝(起始位置)有多远。
咋想起来折腾这玩意儿?
一开始我压根儿就没注意到这东西。平时写代码,结构体成员都是直接点(.)操作符访问,谁还关心它具体在哪儿。可后来我不是琢磨着把代码弄得更明白点儿嘛就想看看结构体成员在内存里头到底是怎么排着的。这一琢磨,就碰上offsetof
。
动手试试!
光说不练假把式,咱得动手试试才知道这玩意儿咋使。我记得,这东西得搁<stddef.h>
头文件里头找。
先整个结构体:
struct MyStruct {

char a;
int b;
short c;
然后,咱就用offsetof
瞧瞧每个成员的“住址”:
#include <stdio.h>
#include <stddef.h>
int main() {
printf("a 的偏移量:%zu\n", offsetof(struct MyStruct, a));
printf("b 的偏移量:%zu\n", offsetof(struct MyStruct, b));
printf("c 的偏移量:%zu\n", offsetof(struct MyStruct, c));
return 0;
跑起来一看,还真有东西!
- a 的偏移量:0
- b 的偏移量:4
- c 的偏移量:8
为啥是这么个结果?
这是因为各个成员之间还可能有空隙,目的是方便快速存取数据,这是为让数据对齐。char
类型的a
占一个字节,int
类型的b
占四个字节,short
类型的c
占俩字节。
这玩意儿到底咋实现的?
光会用还不行,咱得琢磨琢磨它里头是怎么个道道。我搜搜资料,发现这offsetof
还挺有意思,里头用一点小“魔法”。
大概就是这么个意思:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE )0)->MEMBER)
这里头,先把0强转成一个指向TYPE
类型的指针,然后通过这个指针访问MEMBER
成员,再取这个成员的地址。因为结构体的起始地址是0,所以这个成员的地址,就是它相对于结构体起始位置的偏移量。再把这个地址强转成size_t
类型,就得到咱想要的偏移量。
总结一下
今儿个这一通折腾,算是把offsetof
这玩意儿给弄明白。
以后再想知道结构体成员的“住址”,就不用自己在那儿瞎琢磨,直接用offsetof
一瞧,清清楚楚!