📜  OFFSETOF()宏

📅  最后修改于: 2021-05-25 18:31:01             🧑  作者: Mango

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

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

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

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

零强制转换为结构类型,并且访问所需元素的地址,该地址强制转换为size_t 。按照标准, size_t的类型为unsigned int 。整个表达式导致字节数,然后将ELEMENT放置在结构中。

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

#include 
  
#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;
}

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

OFFSETOF(PodType, c);

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

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

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

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

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

参考:

1. Linux内核代码。

2. http://msdn.microsoft.com/en-us/library/dz4y9b9a.aspx

3. GNU C / C++编译器文档

想要从精选的最佳视频中学习和练习问题,请查看《基础知识到高级C的C基础课程》。