【问题标题】:C++ Getting parrent class with pointer arithmetic [duplicate]C ++使用指针算术获取父类[重复]
【发布时间】:2017-08-15 19:36:17
【问题描述】:

在以下代码中:

using Previous = std::atomic<void*>;
template<class T>
struct Element{
    Previous previous;
    T value;
}

我是否可以进行指针运算以从 T* 获取 Element&lt;T&gt;* ? 像这样:

template<class T>
Element<T>* getElement(T* value){
   return static_cast<Element<T>*>(static_cast<void*>(reinterpret_cast<unsigned char *>(value) - sizeof(Previous)));
}

其中T 可能是非标准布局。

附:我清楚地看到我不能为此使用offsetof。但是,可能对于这种特殊情况,指针运算会起作用吗?

【问题讨论】:

  • 我建议减少黑客攻击并更多地修复设计。
  • 只有当结果是指向属于同一数组或该数组末尾的元素的指针时,才允许进行指针运算。 (&amp;x 的行为类似于单元素数组。)其他所有内容都未定义。
  • 我真正想要的是template &lt;typename Object, typename Member&gt; Object* operator-(Member* member, Member Object::* ptr),这样您就可以从指向成员的指针中减去指向成员的指针以获得指向包含对象的指针。

标签: c++


【解决方案1】:

答案是:这取决于编译器!

如果您有一个 64 位编译器并且 sizeof(Previous) 是 4 并且 T 是指针数据类型,那么编译器(至少大多数编译器)将在 previous 和 value 之间添加 4 个额外的字节。

你使用的指针:

(void *)(((unsigned char *)value) - sizeof(Previous)

... 在这种情况下,将指向previous 之后的第一个字节!

但是,您可以将sizeof(Previous) 替换为以下表达式:

(int)&(((Element *)NULL)->value)

(对不起,上面的表达式是C表达式;我的C++不是最好的。)

此表达式应始终为常量:父结构中元素的地址偏移量。


编辑

理论上,可能有编译器会执行NULL 指针检查,这会在使用上述表达式时导致错误。

在这种情况下,下面的表达式将完成这项工作:

((int)&(x.value) - (int)&x)

...而x 是数据类型Element 的任何对象(例如局部变量)。

【讨论】:

  • (int)&amp;(((Element *)NULL)-&gt;value) - 这将返回父值和值之间的偏移量,对吧?
  • @tower123:是的,应该。至少在 C 中是这样。我不知道所有 C++ 变体;例如,C++.NET 根本不允许您进行指针运算...
  • 您需要检查T 的对齐方式以了解引入了多少填充;你不能假设它是 4。
  • @DanielH 我修改了我的答案。
  • 第二句仍然说它会增加 4 个字节,如果 T 是 char、char[12]、uint32_t 或任何其他带有 4- 的类型,则不是真的字节对齐或更少。
猜你喜欢
  • 2014-10-09
  • 1970-01-01
  • 1970-01-01
  • 2012-07-27
  • 2014-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多