4

如何将 void 指针转换为 double,保留存储在 void 指针中的确切二进制文件?我认为这可以用 来完成reinterpret_cast<double>(voidp),但 g++ 不允许我这样做。我知道你可以将 void 指针转换为整数,所以我尝试reinterpret_cast<double>(reinterpret_cast<long>(voidp))了,但显然这也是无效的。sizeof(double)并且sizeof(void*)都是8,所以它不可能是一个大小的东西。我能做些什么来做到这一点吗?

编辑:在这种情况下,double 不是由 void 指针指向的,而是 /is/ void 指针 - 指针本身包含我想要的数据,它不指向我想要的数据。

4

4 回答 4

12

根据定义,直接内存重新解释意味着使用左值。最直接的方法是通过强制转换为引用类型来做到这一点

double d = reinterpret_cast<double &>(voidp);

正如其他答案所建议的那样,您也可以通过指针转换来完成此操作,尽管它使用许多完全不必要的运算符应用程序“重载”了该过程。这两种方法是等价的,因为根据定义reinterpret_cast,引用类型reinterpret_cast<T &>(v)等价于指针版本*reinterpret_cast<T *>(&v)

然而,上述方法存在类型双关问题。从形式上讲,这样做是违法的。在 C++ 中,不允许将void *对象作为对象读取。doubleC++ 中存在直接内存重新解释,用于将对象重新解释为chars 的数组,而不是像上面那样用于任意类型的双关语。即使我们忽略形式问题并坚持纯粹的“实际”考虑,尝试直接将值重新解释void *double值也可能会在执行优化时遵循严格别名语义的编译器中产生完全出乎意料且毫无意义的结果。

一个更好的想法可能是memcpy对象void *double对象

double d;
assert(sizeof d == sizeof voidp); // <- a static assert would be even better
memcpy(&d, &voidp, sizeof d);

或者,在 C 中,您现在可以为此目的使用联合。我还不确定 C++ 的正式许可,但它通常会在实践中起作用。

于 2013-10-15T17:53:57.993 回答
7

memcpy()方法应该是您首选的类型双关语方法:

double d = 100;
void *x;
std::memcpy(&x, &d, sizeof x);

std::cout << x << '\n';

double d2;
std::memcpy(&d2, &x, sizeof d2);

std::cout << d2 << '\n';

您可能认为这会比强制转换慢,但实际上编译器足够聪明,可以识别这里发生的事情并生成最佳代码:http ://blog.regehr.org/archives/959

此外,此方法不会因使用强制转换或联合方法时发生的别名违规而导致未定义的行为。

您可以编写一个bit_cast运算符来使这更方便和更安全:

http://pastebin.com/n4yDjBde

template <class Dest, class Source>
inline Dest bit_cast(Source const &source) {
    static_assert(sizeof(Dest)==sizeof(Source), "size of destination and source objects must be equal");
    static_assert(std::is_trivially_copyable<Dest>::value, "destination type must be trivially copyable.");
    static_assert(std::is_trivially_copyable<Source>::value, "source type must be trivially copyable");

    Dest dest;
    std::memcpy(&dest, &source, sizeof(dest));
    return dest;
}

示例用法:

void *p = ...;
double d = bit_cast<double>(p);

如果你做类型双关语,你应该知道所涉及类型的陷阱值以及你的编译器对陷阱和未指定值的行为。

于 2013-10-15T17:53:46.930 回答
2

完全不建议这样做,但如果必须,请使用:

*reinterpret_cast<double*>(&voidp)
于 2013-10-15T17:47:02.847 回答
-1
void* some_void_data = NULL;
double* as_double = static_cast<double*>(some_void_data);
double as_double_copy = *as_double;
double as_double_copy_one_line = *static_cast<double*>(some_void_data);

显然,您希望在实际使用中将强制转换应用于非空指针。static_cast只能用于从一种指针类型转换为另一种指针类型。如果你想要一个指针的副本,你应该通过取消对强制转换返回的指针的引用来自己执行复制。

是一个很好的铸造资源。

于 2013-10-15T17:49:59.083 回答