C宏扩展说明

时间:2014-06-13 18:25:51

标签: c macros

我继承了很多代码,我对这种扩展感到磕磕绊绊。我理解它的作用,我不明白它是如何做到的。

#define OFFSETOF(structure, item)     ((u16)&(((structure*)0)->item))

更具体地说,除了这部分((structure*)0)之外,我得到了大部分内容。我不知道零正在做什么或者它是什么。

如果你需要知道,'结构'只是typedef struct{},而项目是

中的成员
 struct{
    u32 my_example_item;
}

再次,零点让我感到困惑。

2 个答案:

答案 0 :(得分:2)

  • structure是一种类型
  • (structure*)是一个指针
  • (structure*)0structure*
  • 类型的空指针
  • ->item获取指向
  • 的对象的item成员
  • (((structure*)0)->item)假装在内存中位置0有一个structure,并引用它的项目。
  • &(((structure*)0)->item)获取该项的地址,该地址将等于对象中item的偏移量。此地址的类型为u32*(因为itemu32
  • ((u16)&(((structure*)0)->item))将该地址转换为u16,因此它是适当的偏移类型。

答案 1 :(得分:1)

这类似于C标准头offsetof()中定义的<stddef.h>宏的常见实现。代码实际上具有未定义的行为,但它可能适用于大多数C实现。

它从类型item的开头产生structure的偏移量(以字节为单位)。 structure应该是一个结构类型(它可以是一个联合,但是OFFSETOF总是会产生0),而item是该结构(或联合)类型的成员。

(structure*)0指向structure 的类型的空指针。

((structure*)0)->item是指空指针指向的地址中不存在的item对象的structure成员。是的,这很奇怪。 如果将空指针表示为内存地址0,并且item的偏移量为12字节,则((structure*)0)->item引用的对象位于内存地址这对当前系统的内存模型做了很多假设。这些假设通常是有效的;如果他们不这样做,这件事可能会在你脸上爆炸。

&(((structure*)0)->item)是地址12处神话物体的地址。

最后,((u16)&(((structure*)0)->item))是显式转换为structure*的内存地址12(类型u16)。据推测,u16是无符号的16位整数类型(如果是这样,使用标准uint16_t会更有意义。)

因此,给定结构类型structure和偏移量为12的成员item,此宏将扩展为产生值12的表达式。

请记住,地址(指针值)不是数字;他们在概念上是截然不同的概念。此宏仅适用于使用特定内存模型的系统,该模型不是由C标准指定的。

我不确定为什么结果属于u16类型。标准offsetof宏会生成size_t类型的值。

对于使用不同内存模型的系统(例如,如果空指针表示为all-bits-one或0xdeadbeef),则此OFFSETOF宏将不起作用,并且标准{ {1}}宏必须适合在特定系统上工作。这部分原因offsetof位于标准库中,因此可以以适用于每个系统的方式实现。