【问题标题】:Why offsetof implementations strangely differs on C and C++?为什么 offsetof 的实现在 C 和 C++ 上有奇怪的不同?
【发布时间】:2017-11-10 09:53:53
【问题描述】:

我打开stddef.h 看到了这个:

#if defined _MSC_VER && !defined _CRT_USE_BUILTIN_OFFSETOF
    #ifdef __cplusplus
        #define offsetof(s,m) ((size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
    #else
        #define offsetof(s,m) ((size_t)&(((s*)0)->m))
    #endif
#else
    #define offsetof(s,m) __builtin_offsetof(s,m)
#endif

__cplusplus 的分支(如果是 C++ 编译器)有一个非常奇怪的实现,我认为它是多余的。其他分支(C 编译器的情况)具有更简单的字段偏移计算。我测试了它,它有效。为什么在第一种情况下使用了这种奇怪的强制转换和类型限定符?

【问题讨论】:

  • @RemyLebeau 我想我不同意你的说法。 C++ 转换比 C 转换更安全。但是:C 风格的转换确实有编译时检查:例如,您不能在不相关的类之间进行转换。虽然 C++ 强制转换有更多的编译时检查,但它仍然允许你做无效的事情:例如,你可以在 int 和 float 之间进行 reinterpret_cast:int a = 24; float f = *reinterpret_cast&lt;float*&gt;(&amp;a); 这样编译没有任何错误
  • @bolov 不过,这仍然是指针之间的转换。但是reinterpret_cast 比 C 风格的演员更安全,因为后者会做任何static_castreinterpret_castconst_cast 所做的事情,甚至是前者与后者的某种组合(例如@987654329 @加const_cast)。
  • 顺便说一句,如果用户代码包含空指针取消引用,这将是未定义的行为。但是,这是在平台标题中,并且平台开发人员具有特殊权限……
  • @ArneVogel 是的,我说过 C++ 转换比 C 转换更安全

标签: c++ c offsetof


【解决方案1】:

operator &amp; 可以为m 类型重载,因此&amp;((s*)0)-&gt;m) 将调用operator &amp; 而不是使用m 的地址。

并且const volatile 存在于reinterpret_cast 的类型中,因此即使mconst 和/或volatile 也可以工作。

请注意,在 C++11 中,std::addressof(x) 始终采用x 的地址,而不管operator &amp; 是否重载。它的实现方式可能与您在问题中看到的类似。

【讨论】:

  • 请注意,C++11 及更高版本有std::addressof() 来处理operator&amp; 问题。 offsetof() 可以写成#define offsetof(s,m) ((size_t)std::addressof(((s*)0)-&gt;m))
  • @RemyLebeau 好点。我想了想,但最后没有提。现在做了。
猜你喜欢
  • 1970-01-01
  • 2010-10-17
  • 2013-05-28
  • 2017-08-08
  • 1970-01-01
  • 2015-09-24
  • 2012-06-02
  • 1970-01-01
  • 2011-11-03
相关资源
最近更新 更多