1. 主页
  2. 文档
  3. C语言教程
  4. C语言预处理器
  5. OFFSETOF() 宏

OFFSETOF() 宏

我们知道结构中的元素将按其声明的顺序存储。

如何提取结构中元素的位移?我们可以利用offsetof宏。

通常我们将结构和联合类型(或 具有普通构造函数的类)称为普通旧数据(POD)类型,它们将用于聚合其他数据类型。以下非标准宏可用于从结构变量的基地址获取元素的位移(以字节为单位)。

#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))

零被转换为结构类型并访问所需元素的地址,该地址被转换为size_t。根据标准 size_tunsigned int类型 。整体表达式会导致 ELEMENT 被放置在结构中之后的字节数。

例如,以下代码返回 16 个字节(在 32 位机器上考虑填充)作为结构 Pod 中字符变量c 的位移。

#include <stdio.h>

#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))

typedef struct PodTag
{
int i;
double d;
char c;
} PodType;

int main()
{
printf("%d", OFFSETOF(PodType, c) );

getchar();
return 0;
}

在上面的代码中,下面的表达式将返回结构体PodType中元素c的位移。

OFFSETOF(PodType, c);

在预处理阶段之后,上述宏扩展为

((size_t)&(((PodType *)0)->c))

由于我们将 0 视为结构变量的地址,因此 c 将放置在其基地址的 16 个字节之后,即 0x00 + 0x10。对结构元素(在本例中为 c)应用 & 会返回元素的地址,即 0x10。将地址转换为unsigned int (size_t) 会导致元素放置在结构中的字节数。

注意:我们可能认为地址运算符 & 是多余的。如果宏中没有地址运算符,代码会取消引用位于 NULL 地址的结构元素。它会在运行时导致访问冲突异常(分段错误)。

请注意,根据编译器行为,还有其他方法可以实现 offsetof 宏。最终目标是提取元素的位移。我们将在另一篇文章中看到在喜欢的列表中使用 offsetof 宏来连接相似对象(例如线程池)的实际用法。

 

这篇文章对您有用吗?