【问题标题】:What is this macro exactly doing?这个宏到底在做什么?
【发布时间】:2012-03-07 09:41:43
【问题描述】:
#define offsetof(type, member)  ((size_t)(&((type *)0)->member))

我不明白 (&((type *)0)->member) 这到底是在告诉我什么.....

这里的类型可能是一个结构或其他东西??...

更具体地说,这里的 0 告诉我什么??

【问题讨论】:

标签: c pointers structure offset


【解决方案1】:

这是确定结构字段的偏移量。它的工作原理是使用 0 作为结构的地址,然后询问字段的地址:

(type *)0

是0作为指向type的指针

&((type *)0)->member

是该假设结构的member 成员的地址。如果结构体的地址为0,则成员的地址与结构体开头的偏移量相同。

((size_t)(&((type *)0)->member))

该地址是否转换为 size_t 以成为偏移的正确类型。

【讨论】:

  • 是的,我知道它给了我结构的偏移量,但我不明白为什么我们在这里给 type* ......它应该适用于 (&((type )0)->成员)...我错过了什么。 ???
  • 是的。 (type)0 不是左值,也没有地址。您需要它的地址(无值!)为 0 的对象。顺便说一句,我很确定整个事情都是 UB。
  • @asaelr - 奇怪的是,标准优化了 &*(type *)0&((type *)0)[x] 但不是 &((type *)0)->member - 但它“通常”有效。在没有它的平台上,使用(type *)1024 几乎总是有效的——它应该为几乎任何类型对齐。请记住在宏末尾从最终结果中减去该数字。
  • 如果我使用 Type*,它应该给出一个 seg 错误正确...???.. 所以,我认为 ((type)0) 应该可以工作
  • @Invictus 不,因为您永远不会访问该地址的数据:您只是将其用作参考。您无需知道地址(零)at 是什么即可找到偏移量。 (但如果你看的话,是的,你会出现段错误(取决于你的系统)。
【解决方案2】:

宏将地址 (0) 转换为声明的类型(“类型”),然后访问字段(“成员”)并获取地址。结果是字段的地址,从地址 0 开始的偏移量,给出了从类型(结构/联合)开始到字段的偏移量。

【讨论】:

  • 是的,我知道它给了我结构的偏移量,但我不明白为什么我们在这里给 type* ......它应该适用于 (&((type )0)->成员)...我错过了什么。 ???
  • 你的常量存储在哪里?将零更改为任意数字 - '123' 说,无论哪种方式,你都会要求编译器给你一个常量的地址加上一个成员的偏移量,而不是一个 address的地址> 加上成员的偏移量,这就是为什么你要转换为指针。
  • 你能解释一下这里的常量是什么,这里的成员是什么......我有点困惑......
【解决方案3】:

我是这样分解的:

  1. (type *)0 - 将0 转换为指向“type”类型的指针。即想象一下,在内存地址 0 处有一个“type”类型的对象。

  2. ->member - 查看名为 member 的字段的对象。

  3. & - 获取地址。

你也可以这样写:

((size_t)((&((type *)x)->member) - x))

但我们在作弊并使用0,所以最后没有偏移量可以起飞。

【讨论】:

  • 是的,我知道它给了我结构的偏移量,但我不明白为什么我们在这里给 type* ......它应该适用于 (&((type )0)->成员)...我错过了什么。 ???
  • - x 位不应在 size_t 演员之前的括号中,否则它将从 type * 中减去 x - 这可能与减去 @987654334 不同@ 来自一个数字。
  • Chris - 我添加了更多括号来解决这个问题并使其更简单 - 仔细观察:-)。
  • 如果我使用 Type*,它应该给出一个 seg 错误正确...???.. 所以,我认为 ((type)0) 应该可以工作...
猜你喜欢
  • 2018-04-19
  • 1970-01-01
  • 2022-01-10
  • 1970-01-01
  • 1970-01-01
  • 2021-03-07
  • 2014-12-01
  • 2012-10-16
  • 1970-01-01
相关资源
最近更新 更多