写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明
考察:
offsetof
宏的实现
描述:
C 库宏 offsetof(type, member-designator) 会生成一个类型为 size_t 的整型常量,它是一个结构成员相对于结构开头的字节偏移量。成员是由 member-designator 给定的,结构的名称是在 type 中给定的。
声明:
下面是 offsetof() 宏的声明。
offsetof(type, member-designator)
参数说明:
- type -- 这是一个 class 类型,其中,member-designator 是一个有效的成员指示器。
- member-designator -- 这是一个 class 类型的成员指示器。
返回值:
该宏返回类型为 size_t 的值,表示 type 中成员的偏移量。
实例:
#include <stddef.h>
#include<stdio.h>
struct S
{
char c1;
int i;
char c2;
};
int main()
{
printf("S 结构中的 c1 偏移 = %d 字节。\n", (int)offsetof(struct S,c1));
printf("S 结构中的 i 偏移 = %d 字节。\n", (int)offsetof(struct S,i));
printf("S 结构中的 c2 偏移 = %d 字节。\n", (int)offsetof(struct S,c2));
}
模拟实现:
具体代码实现:
#define offsetof(TYPE,MEMBER) (size_t)(&((TYPE *)0) -> MEMBER)
struct S
{
int a;
float f;
char c;
short sh;
};
int main()
{
printf("S 结构中的 a 偏移 = %d 字节。\n", offsetof(struct S,a));
printf("S 结构中的 f 偏移 = %d 字节。\n", offsetof(struct S,f));
printf("S 结构中的 c 偏移 = %d 字节。\n", offsetof(struct S,c));
printf("S 结构中的 sh 偏移 = %d 字节。\n", offsetof(struct S,sh));
return 0;
}
1. (type *)0,可以理解为把 0 地址强制转换为 type 结构体类型的指针,此时 0 就成了 type 结构体的首地址,指向该结构体,既然为结构体指针,那么自然可以引用该结构体的成员,所以 (type *)0)->member 的整体意义就是引用 type 结构体的成员 member。
2. &(type *)0)->member) 便是取该结构体成员 member 的地址。而结构体起始地址为 0 时,结构体成员的地址为多少,其相对于结构体的偏移量就为多少。所以此时结构体类型成员的地址就是该成员相对结构体起始地址的偏移量。
3. 经过上面的分析之后,这段代码的逻辑就很简单了,通过 &((TYPE *)0)->MEMBER) 先取 TYPE 结构体类型成员的地址,强制转换成 size_t 类型后返回结构体类型成员的地址。又因为结构体起始地址为 0 时,结构体成员的地址就是偏移量,所以最后 offsetof 便返回结构体中某个成员相对于结构体起始地址的偏移量。