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