0

以下代码及其输出:

#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)从地址(值)开始的类型。因此,对于给定的结构,预期值为 0,即 offsetof 为 b,但由于我们使用不同的值进行类型转换,我们得到不同的偏移量。请让我知道我的理解是否正确。我只是想了解文字是如何进行类型转换的及其含义。这在Linux内核中使用。因此也标记了它们。

4

1 回答 1

2

offsetof是一个标准设施。C 标准定义它以某种方式运行,但没有定义编译器如何实现它。大多数编译器依赖于未定义的行为,为了offsetof实现而定义了一种特殊情况。

你所做的在语言语义方面是无稽之谈。将值2视为指针是未定义行为的典型示例。

语言的设计意图不是用户可以自己定义的offsetof,所以最好不要尝试。

“在幕后”,是的,指针通常是保存在机器寄存器中的标量,标量算术用于获取结构成员的地址。执行相同的算术以获取“位置零”处的对象的地址会产生其在任何对象中的通用偏移量。使用除零以外的整数作为位置可能会产生算术结果,也可能不会。(它通常会,但这个想法是无稽之谈。)

尝试使用概念上无意义的程序是发现系统如何工作的一种冒险方式,因为您冒着这样的风险,它会标记错误或在检测到有问题时采取捷径。

于 2013-11-10T02:45:28.063 回答