将reinterpret_cast指针传递为void *

时间:2017-02-21 11:54:47

标签: c++ function c++11 pointers void

在以下code -

#include <iostream>
using namespace std;

struct S1{
    int a; int b; int c; int d;
};

struct S{
    int a; int b;
};

int main() {
    S1 obj1;
    obj1.a = 1;
    obj1.b = 2;
    obj1.c = 3;
    obj1.d = 4;

    cout << obj1.a << " "
         << obj1.b << " "
         << obj1.c << " "
         << obj1.d << "\n";

    // more code

    auto ptr = reinterpret_cast<S *>(&obj1);
    cout << ptr->a << " " << ptr->b << "\n";

    // more code

    // someFunc(ptr, sizeof(obj1));
}

我将值分配给结构S1的成员,然后通过S原始reinterpret_castS1将其作为结构S指针用于其他地方。这很好。

现在提前一点,我有一个函数someFunc(const void *ptr, int len),它将const void *指针和长度传递给正在传递的结构。在这种情况下,它应该将S1结构传递给它,并且在其中有一些memcpy调用来复制结构并处理该副本。 我可以这样做吗? -

// more code

   someFunc(ptr, sizeof(obj1));
}

意味着将reinterpret_cast指针传递给此函数和原始S1结构的大小,或者我是否必须再次reinterpret_cast将其返回S1然后再次传递指针

不必reinterpret_cast再次使用原始类型可以为类似类型S1保存一些切换案例。请注意,someFunc可以根据传入的size轻松找到类型,因为这些相似类型的大小差异很大。

4 个答案:

答案 0 :(得分:2)

struct的地址是struct的第一个字节的地址。即使我在标准中找不到任何引用,它也是C ++中常见的习惯用法(就像在C中一样)将指向POD结构(或多或少是C结构)的指针转换为指向初始子序列的指针那个班。转换为void *时,两者都会给出相同的值。

所以用你的记号:

someFunc(ptr, sizeof(obj1));

someFunc(obj1, sizeof(obj1));

是完全相同的电话。

答案 1 :(得分:1)

是的,

     someFunc(ptr, sizeof(obj1));

很好......但仅仅因为obj1 实际类型为S1。我对你的评论有点怀疑&#34;保存一些像S1和#34;类似类型的开关案例。

答案 2 :(得分:1)

  

我正在为结构S1的成员分配值,然后通过将原始S1重新解释为将其作为结构S指针在其他地方使用它们。这样可以正常工作。

     

现在有点提前,我有一个函数someFunc(const void * ptr,int len),它将const void *指针和长度传递给正在传递的结构。

     

我可以这样做吗?

你可以。你永远不应该。

你的代码中应该有这样一个API的唯一原因是,如果你没有写它但必须使用它,没有权利触摸它所在的代码,和/或没有时间预算来包装或重写它(这应该需要一个小时左右)。

替代代码,使用继承(避免reinterpret_cast和整个问题):

struct S { int a, b; }; // defines common behavior between structures
                        // this is what base classes are for

struct S1: S { int c, d; }; // inherit S

someFunc:

auto someFunc(S& sref);

S s{1, 2};
S1 s1{1, 2, 3, 4};
someFunc(s); // works
someFuncf(s1); // also works
  

不必将reprepret_cast再次重新设置为原始类型将为我节省一些类似类型的开关案例。

必须在用户类型(您的S结构)上键入reinterpret_cast表示您没有将常见行为提取到公共基类/结构中。

答案 3 :(得分:1)

  

我正在为结构S1的成员分配值,然后通过将原始S1重新解释为将其作为结构S指针在其他地方使用它们。这样可以正常工作。

这是未定义的行为。一个可能的症状是它“工作正常”。

S1S是布局兼容的,但它们不是同一个对象。 S1S住在该位置,而不是两者。

访问实际上并不存在未定义行为的对象。

你想要的是指针 - 不可转换。

这是合法的C和C ++:

struct S{
  int a; int b;
};
struct S1{
  S s;
  int c; int d;
};

现在,可以将指向S1的指针重新解释为指向S的指针,abs.a相同原始s.b中的S1

在C ++中,这也可以通过继承来完成:

struct S1:S {
  int c; int d;
};

在这两种情况下,都存在S1S对象,因此您永远不会访问不存在的对象。

你所做的事通常会奏效;但在C ++标准下,它是未定义的行为。

作为一个实际问题,优化器可以假设它永远不会发生,不能访问S可以修改S1的状态,反之亦然,这可能会导致程序中出现意外行为。当您将程序升级到链接时间优化时,可能会自发地出现新的和极其危险的行为。

S1 obj1 { 1,2,3,4 };
static_cast<S*>(&obj1).a=99;
std::cout << obj1.a; // can legally print out 1, or anything else really
std::cout << obj1.a; // it could now print out 99.  Why?  Undefined behavior

一旦你有实际的指针可互换性,C ++标准确保:

S1 obj1 { 1,2,3,4 };
auto* s = reinterpret_cast<S*>(&obj1);
void* ptr = s;
Assert( static_cast<S1*>(ptr) == &obj1 );

Assert通过。