为什么宏的抵消必要?

我对C语言很陌生,刚刚学习了结构和指针。

我的问题与我最近看到的宏观offsetof有关。 我知道它是如何工作的,以及背后的逻辑。

<stddef.h>文件中,定义如下:

#define offsetof(type,member) ((unsigned long) &(((type*)0)->member))

我的问题是,如果我有一个结构如下所示:

struct test {
    int field1:
    int field2:
};

struct test var;

为什么我不能直接获取field2的地址为:

char * p = (char *)&var;
char *addressofField2 = p + sizeof(int);

而不是写这样的东西

field2Offset = offsetof (struct test, field2);

然后将偏移量值添加到var的起始地址?

有什么区别吗? 使用更高效的offsetof


C编译器通常会在struct成员之间添加额外的填充位或字节,以提高效率并保持字对齐的整数(在某些体系结构中需要避免总线错误,而在某些体系结构中则需要避免效率问题)。 例如,在许多编译器中,如果你有这个struct

struct ImLikelyPadded {
    int x;
    char y;
    int z;
};

你可能会发现sizeof(struct ImLikelyPadded)是12而不是9,因为编译器会在单字节char y和字大小int z之间插入三个额外的填充字节。 这就是为什么offsetof非常有用 - 它可以让你确定事物的真正含义,甚至包括填充字节,并且具有高度的可移植性。


与数组不同,struct的内存布局并不总是连续的。 编译器可能会添加额外的字节,以便对齐内存。 这被称为padding

由于填充,我们很难手动找到成员的位置。 这也是我们总是使用sizeof来查找结构大小的原因。

Offsetof,宏可以让你从结构的声明位置找出结构成员的距离,偏移量。

如果在Linux内核的container_of宏中看到offsetof,则可以使用它。 通过这个宏,可以查找节点的起始位置,给定成员在通用包含双向链表中的地址


正如其他答案中已经提到的那样,填充是其中一个原因。 我不会重复已经说过的话。

使用offsetof宏而不是手动计算偏移量的另一个好理由是,您只需编写一次即可。 想象一下,如果您需要更改field1的类型或插入或删除field2前面的一个或多个字段,会发生什么情况。 使用你的手工计算,你必须找到并改变它的所有事件。 缺少其中一个会产生很难找到的神秘错误。

在这种情况下,使用offsetof编写的代码不需要任何更新。 编译器负责处理下一个编译中的所有内容。

offsetof ,使用offsetof的代码更清晰。 这个宏是标准的,它的功能被记录下来。 读取代码的同伴程序员立即理解它。 理解手工代码尝试的方式并不那么容易。

链接地址: http://www.djcxy.com/p/90277.html

上一篇: Why is the offsetof macro necessary?

下一篇: Window.screen in Internet Explorer and more than one monitor