为什么我不能reinterpret_cast uint 到 int?
Why can't I reinterpret_cast uint to int?
这就是我想做的:
const int64_t randomIntNumber = reinterpret_cast<int64_t> (randomUintNumber);
其中随机UintNumber 的类型为 uint64_t
。
错误是 (MSVC 2010):
错误 C2440:"reinterpret_cast":无法从"常量uint64_t"转换 到"int64_t" 1> 转换是有效的标准转换, 可以隐式执行,也可以使用 static_cast、C 样式执行 演员或功能式演员表
为什么不编译? 两种类型具有相同的位长度,这不是reinterpret_cast的用途吗?
reinterpret_cast
的目的。所有允许的带有reinterpret_cast
的转换都涉及指针或引用,但整数或枚举类型可以reinterpret_cast
到自身。这一切都在标准中定义,[expr.reinterpret.cast]
.
我不确定你在这里要实现什么,但如果你想让randomIntNumber
具有与randomUintNumber
相同的价值,那就做
const int64_t randomIntNumber = randomUintNumber;
如果这会导致编译器警告,或者您只是想更明确,那么:
const int64_t randomIntNumber = static_cast<int64_t>(randomUintNumber);
如果randomUintNumber
小于 263,则转换结果的值与输入值相同。否则,结果是实现定义的,但我希望所有具有int64_t
的已知实现都会定义它来做显而易见的事情:结果相当于输入模 264。
如果您希望randomIntNumber
具有与randomUintNumber
相同的位模式,那么您可以这样做:
int64_t tmp;
std::memcpy(&tmp, &randomUintNumber, sizeof(tmp));
const int64_t randomIntNumber = tmp;
由于int64_t
保证使用 2 的补码表示,因此您希望实现定义 static_cast
对于超出范围的值 uint64_t
具有与此相同的结果。但在标准 AFAIK 中实际上并不能保证。
即使randomUintNumber
是编译时常量,不幸的是,这里的randomIntNumber
也不是编译时常量。但是,编译时常量有多"随机"呢?;-)
如果您需要解决此问题,并且您不相信实现在将超出范围的无符号值转换为有符号类型方面是明智的,那么如下所示:
const int64_t randomIntNumber =
randomUintNumber <= INT64_MAX ?
(int64_t) randomUintNumber :
(int64_t) (randomUintNumber - INT64_MAX - 1) + INT64_MIN;
现在,我赞成在可能的情况下编写真正可移植的代码,但即便如此,我认为这近乎偏执狂。
顺便说一句,你可能会想写这个:
const int64_t randomIntNumber = reinterpret_cast<int64_t&>(randomUintNumber);
或等效:
const int64_t randomIntNumber = *reinterpret_cast<int64_t*>(&randomUintNumber);
这并不能完全保证有效,因为尽管它们存在int64_t
和uint64_t
保证是相同大小的有符号类型和无符号类型,但它们实际上并不能保证是标准整数类型的有符号和无符号版本。因此,无论此代码是否违反严格别名,都是特定于实现的。违反严格别名的代码具有未定义的行为。以下内容不违反严格混叠,并且只要 randomUintNumber
中的位模式是值 long long
的有效表示形式,就可以
unsigned long long x = 0;
const long long y = reinterpret_cast<long long &>(x);
因此,在int64_t
和uint64_t
是用于long long
和unsigned long long
的typedefs的实现中,那么我reinterpret_cast
就可以了。与实现定义的将超出范围的值转换为有符号类型一样,您可能期望实现的明智做法是使它们成为相应的有符号/无符号类型。因此,就像static_cast
和隐式转换一样,您希望它在任何合理的实现中工作,但实际上并不能保证。
在这些情况下使用static_cast
。 我想语言设计者以他们所有的智慧决定它被认为不够"不安全",无法保证reinterpret_cast
。
不,不是。 reinterpret_cast
主要用于将现有存储位重新解释为与其不同的类型。这些解释中有很多是依赖于实现的,标准列出了一个特定的(在这里引用相当长)列表,这些列表可以用reinterpret_cast
完成(主要是在不同的指针/引用类型之间进行转换),但说:
不能使用 显式执行其他转换 reinterpret_cast。
在您的情况下,您可能希望转换类型,而不是重新解释现有存储。为此,请使用static_cast
。
来自 C++11 标准(N3376) 5.2.10.1 本文档,第 101 页:
下面列出了可以使用reinterpret_cast显式执行的转换。不其他转换可以使用reinterpret_cast显式执行。
如果类型相同,则允许从整型到整型的唯一转换是事实。
其他涉及指针。
用memcpy
重新解释位模式,用static cast
转换类型
使用reinterpret_cast
您违反了strict aliasing
.这很糟糕,因为它最终会导致未定义的行为(也许您使用新的编译器版本编写了故障。什么是严格别名规则,我们为什么关心?是一篇很棒的文章,描述了问题及其解决方案(也许跳过冗长的部分"现在,到规则手册";))。它建议memcpy
并争辩说,编译器优化无论如何都会跳过复制。
法典
交互式代码在这里。在您的特定情况下,所有选项都会产生相同的结果。当玩newType
和randomUintNumber
时,这种情况会发生变化。
#include <iostream>
#include <cstring>
int main()
{
typedef int64_t newType; // try: double, int64_t
uint64_t randomUintNumber = INT64_MAX + 10000; // try: 64000, INT64_MIN, INT64_MAX, UINT64_MAX, INT64_MAX + 10000
std::cout << "INT64_MIN: " << INT64_MIN << std::endl;
std::cout << "UINT64_MAX: " << UINT64_MAX << std::endl;
std::cout << "INT64_MAX: " << INT64_MAX << "nn";
std::cout << "randomUintNumber: " << randomUintNumber << "nn";
// const int64_t randomIntNumber = reinterpret_cast<int64_t> (randomUintNumber);
std::cout << "as "const int64_t randomIntNumber = reinterpret_cast<int64_t> (randomUintNumber);" does not work, here are some options ...nn";
std::cout << "BAD [undefined behavior!]:" << std::endl;
const newType a = reinterpret_cast<int64_t&> (randomUintNumber);
std::cout << "treinterpret_cast<int64_t&> (randomUintNumber): " << a << std::endl;
const newType b = reinterpret_cast<int64_t&&> (randomUintNumber);
std::cout << "treinterpret_cast<int64_t&&> (randomUintNumber): " << b << std::endl;
std::cout << "nGOOD: " << std::endl;
const newType c = (int64_t) randomUintNumber;
std::cout << "t(int64_t) randomUintNumber [static cast, sometimes reinterprets bit pattern]: " << c << std::endl;
const newType d = static_cast<int64_t>(randomUintNumber);
std::cout << "tstatic_cast<int64_t>(randomUintNumber) [the same as before]: " << d << std::endl;
static_assert(sizeof(uint64_t) == sizeof(newType), "should not be taken for granted ...");
newType eNotConst;
std::memcpy(&eNotConst, &randomUintNumber, sizeof(uint64_t));
const newType e = eNotConst;
std::cout << "tstd::memcpy(&eNotConst, &randomUintNumber, sizeof(uint64_t)); [definately reinterprets bit pattern]: " << e << std::endl;
return 0;
}
输出
INT64_MIN: -9223372036854775808
UINT64_MAX: 18446744073709551615
INT64_MAX: 9223372036854775807
randomUintNumber: 9223372036854785807
as "const int64_t randomIntNumber = reinterpret_cast<int64_t> (randomUintNumber);" does not work, here are some options ...
BAD [undefined behavior!]:
reinterpret_cast<int64_t&> (randomUintNumber): -9223372036854765809
reinterpret_cast<int64_t&&> (randomUintNumber): -9223372036854765809
GOOD:
(int64_t) randomUintNumber [static cast, sometimes reinterprets bit pattern]: -9223372036854765809
static_cast<int64_t>(randomUintNumber) [the same as before]: -9223372036854765809
std::memcpy(&eNotConst, &randomUintNumber, sizeof(uint64_t)); [definately reinterprets bit pattern]: -9223372036854765809
为什么不编译?
因为这两种类型都不是指针。
两种类型具有相同的位长度,
为什么会这样呢?如果它们是指针,也许它们指向相同大小的东西会很重要,但它们不是指针。
这不是reinterpret_cast的目的吗?
不,reinterpret_cast
用于指针转换。你可以通过在演员阵容内放一个&
,在演员表外放一个*
来做你想做的事。这就是重新诠释演员表的目的。
reinterpret_cast
用于将对象的存储重新解释为不同的对象。如果您不想通过标准措辞,您可以在此处找到reinterpret_cast
可以做的所有事情。通常,您可以记住必须使用指针类型。
因此,如果您真的想将用于uint64_t
的位重新解释为 int64_t
,那么这样做:
int64_t randomIntNumber = reinterpret_cast<int64_t&> (randomUintNumber);
但是,如果您只想转换对象,请尽可能保留其值......只需按照编译器的建议进行操作,然后改用static_cast
即可。
- 为什么在全局范围内使用"extern int a"似乎不行?
- int(c) 和 c-'0' 之间的区别。C++
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 为什么野牛仍在使用"int yylex(void)",却找不到"int yylex(YYS
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 是否可以从int转换为enum类类型
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 向量 <int> a {N, 0} 和 int arr a[N] = {0} 的时间复杂度有什么区别
- 'short int'持有的值溢出,但"自动"不会溢出?
- 如何在C++中将一个无符号的 int 转换为两个无符号的短裤?
- 调用'begin(int [n])'没有匹配函数
- 没有显式声明的int[]中的foreach
- 在c++中访问int到类对象的映射时出错
- 为什么我无法更改"set<set>"循环中的值<int>
- 定义 uint= "unsigned int" 没有像我在 Visual Studio 中使用 nvcc 时预期的那样应用
- 在 jsoncpp 中区分 int 和 uint 类型
- 使用librapidjson将混合JSON数字数组转换为int、uint、float
- 为什么我不能reinterpret_cast uint 到 int?
- 将声明的 INT/UINT 的八进制/十六进制分配给另一个变量