以下代码及其输出:
#include <stdio.h>
int x = 0;
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)x)->MEMBER)
#define offsetof_1(TYPE, MEMBER) ((size_t) &((TYPE *)1)->MEMBER)
#define offsetof_2(TYPE, MEMBER) ((size_t) &((TYPE *)2)->MEMBER)
#define offsetof_3(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
struct test{};
struct m {
int b;
char w;
struct test t;
int c;
};
int main(void) {
printf("Checking:%x\n",offsetof(struct m,b));
printf("Checking:%x\n",offsetof_1(struct m,b));
printf("Checking:%x\n",offsetof_2(struct m,b));
printf("Checking:%x\n",offsetof_3(struct m,b));
return 0;
}
Output:
Checking:0
Checking:1
Checking:2
Checking:0
我想了解这里使用的类型转换。我认为,编译器如何处理它将(type *)(value)
视为从address(value)开始的类型。因此,对于给定的结构,期望值为0,即。 offsetof是b,但是由于我们使用不同的类型进行类型转换,我们得到不同的偏移量。如果我的理解是正确的,请告诉我。我只是想了解文字的类型化及其含义。这用于Linux内核。因此也标记它们。
答案 0 :(得分:2)
offsetof
是标准设施。 C标准将其定义为以某种方式运行,但没有定义编译器如何实现它。大多数编译器依赖于未定义的行为,为了offsetof
实现而定义了一个特例。
你所做的就是语言语义而言是无稽之谈。将值2
视为指针是未定义行为的典型示例。
用户无法定义自己的offsetof
语言的设计意图,因此最好不要尝试。
“引擎盖下”,是指针通常是机器寄存器中保存的标量,标量算法用于获取结构成员的地址。执行相同的算术以在“位置零”处获取对象的地址,在任何对象内产生其通用偏移。使用除零之外的整数作为位置可能产生算术结果,或者它可能不会。 (它通常会,但这个想法是无稽之谈。)
尝试使用概念性无意义的程序是发现系统工作方式的一种危险方法,因为它会冒着标记错误或采取检测到错误的快捷方式的风险。