C++从类型“void*”转换为类型“double”无效

C++ invalid cast from type ‘void*’ to type ‘double’

本文关键字:类型 无效 double 转换 void C++      更新时间:2023-10-16

如何将 void 指针转换为双精度,同时保留存储在 void 指针中的确切二进制文件?我认为这可以用reinterpret_cast<double>(voidp)来完成,但 g++ 不允许我。我知道您可以将 void 指针转换为整数,所以我尝试了reinterpret_cast<double>(reinterpret_cast<long>(voidp)),但显然这也是无效的。 sizeof(double)sizeof(void*)都是8,所以不可能是尺寸问题。我能做些什么来实现这一目标吗?

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

根据定义,直接记忆重新解释意味着使用左值。最直接的方法是通过强制转换为引用类型来执行此操作

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

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

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

更好的主意可能是将void *对象memcpydouble对象

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

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

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);

如果您确实使用类型双关语,则应注意所涉及的类型的陷阱值以及编译器使用陷阱和未指定值的行为。

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

*reinterpret_cast<double*>(&voidp)
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只能用于从一种指针类型转换为另一种指针类型。如果你想要指针的副本,你应该通过取消引用强制转换返回的指针来自己执行复制。

这是一个很好的选角资源。