C++从类型“void*”转换为类型“double”无效
C++ invalid cast from type ‘void*’ to type ‘double’
如何将 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 *
对象memcpy
到double
对象
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
只能用于从一种指针类型转换为另一种指针类型。如果你想要指针的副本,你应该通过取消引用强制转换返回的指针来自己执行复制。
这是一个很好的选角资源。
- 具有引用返回类型的重写方法上的协变返回类型无效
- 使用 std::future 的不完整类型无效使用
- 类指针和类指针指向二进制运算符+的类型无效的操作数
- 静态类模板成员:将"sizeof"应用于不完整类型无效
- 数组的类型无效
- 返回并强制转换数组指针(错误:数组下标的类型..无效)
- 错误:数组下标'double*[double]'的类型无效
- 数组下标错误的类型无效
- 协变返回类型无效的转换错误
- 在代码块错误中收到此错误:数组下标'main()::fields[int]'的类型无效
- 3 错误:错误:未在此范围内声明'Entry'。错误:模板参数 1 无效。错误:令牌之前声明中的类型无效'('
- 类成员数组的实现:数组下标的类型无效
- 别名模板、部分专用化和无效参数类型无效
- 数组下标'int [5][float]'的类型无效
- 数组下标的类型无效
- 是否存在对类型名称有效但对基本类型无效的语言构造
- 编译错误 - 数组下标'char[int]'的类型无效
- 使用指向结构数组的指针的参数类型无效
- 使用类模板初始化下标重载函数中的引用类型无效
- 对模板和decltype使用不完整类型无效