为什么我不能将 uint 重新解释为 int? [英] Why can't I reinterpret_cast uint to int?

查看:39
本文介绍了为什么我不能将 uint 重新解释为 int?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我想做的:

const int64_t randomIntNumber = reinterpret_cast;(randomUintNumber);

其中 randomUintNumber 的类型为 uint64_t.

Where randomUintNumber is of type uint64_t.

错误是(MSVC 2010):

The error is (MSVC 2010):

错误 C2440:reinterpret_cast":无法从const uint64_t"转换to 'int64_t' 1> 转换是有效的标准转换,可以隐式执行,也可以使用 static_cast,C 风格演员表或函数式演员表

error C2440: 'reinterpret_cast' : cannot convert from 'const uint64_t' to 'int64_t' 1> Conversion is a valid standard conversion, which can be performed implicitly or by use of static_cast, C-style cast or function-style cast

为什么不编译?两种类型都有相同的位长,这不是 reinterpret_cast 的用途吗?

Why doesn't it compile? both types have the same bit length, isn't it what reinterpret_cast is intended for?

推荐答案

因为这不是 reinterpret_cast 的用途.reinterpret_cast 允许的所有转换都涉及指针或引用,但整数或枚举类型可以是 reinterpret_cast 自身的例外.这一切都在标准中定义,[expr.reinterpret.cast].

Because that's not what reinterpret_cast is for. All the permitted conversions with reinterpret_cast involve pointers or references, with the exception that an integer or enum type can be reinterpret_cast to itself. This is all defined in the standard, [expr.reinterpret.cast].

我不确定您要在这里实现什么,但如果您希望 randomIntNumber 具有与 randomUintNumber 相同的值,那么就这样做

I'm not certain what you're trying to achieve here, but if you want randomIntNumber to have the same value as randomUintNumber, then do

const int64_t randomIntNumber = randomUintNumber;

如果这会导致编译器警告,或者您只想更明确,那么:

If that results in a compiler warning, or if you just want to be more explicit, then:

const int64_t randomIntNumber = static_cast<int64_t>(randomUintNumber);

如果 randomUintNumber 小于 263,则转换结果与输入具有相同的值.否则结果是实现定义的,但我希望所有具有 int64_t 的已知实现都会定义它来做显而易见的事情:结果相当于输入模 264.

The result of the cast has the same value as the input if randomUintNumber is less than 263. Otherwise the result is implementation-defined, but I expect all known implementations that have int64_t will define it to do the obvious thing: the result is equivalent to the input modulo 264.

如果您希望 randomIntNumber 具有与 randomUintNumber 相同的位模式,那么您可以这样做:

If you want randomIntNumber to have the same bit-pattern as randomUintNumber, then you can do this:

int64_t tmp;
std::memcpy(&tmp, &randomUintNumber, sizeof(tmp));
const int64_t randomIntNumber = tmp;

由于 int64_t 保证使用二进制补码表示,您会希望实现定义 static_cast 具有与此相同的结果uint64_t 的值超出范围.但在标准 AFAIK 中实际上并不能保证.

Since int64_t is guaranteed to use two's complement representation, you would hope that the implementation defines static_cast to have the same result as this for out-of-range values of uint64_t. But it's not actually guaranteed in the standard AFAIK.

即使 randomUintNumber 是一个编译时常量,不幸的是这里 randomIntNumber 不是一个编译时常量.但是,编译时常量有多随机"?;-)

Even if randomUintNumber is a compile-time constant, unfortunately here randomIntNumber is not a compile-time constant. But then, how "random" is a compile-time constant? ;-)

如果您需要解决这个问题,并且您不相信实现将超出范围的无符号值转换为有符号类型是明智的,那么可以这样:

If you need to work around that, and you don't trust the implementation to be sensible about converting out-of-range unsigned values to signed types, then something like this:

const int64_t randomIntNumber = 
    randomUintNumber <= INT64_MAX ? 
        (int64_t) randomUintNumber :
        (int64_t) (randomUintNumber - INT64_MAX - 1) + INT64_MIN;

现在,我赞成在可能的情况下编写真正可移植的代码,但即便如此,我认为这已接近妄想症.

Now, I'm in favour of writing truly portable code where possible, but even so I think this verges on paranoia.

顺便说一句,你可能会想这样写:

Btw, you might be tempted to write this:

const int64_t randomIntNumber = reinterpret_cast<int64_t&>(randomUintNumber);

或等效:

const int64_t randomIntNumber = *reinterpret_cast<int64_t*>(&randomUintNumber);

这并不能完全保证工作,因为虽然它们存在的地方 int64_tuint64_t 保证是相同大小的有符号类型和无符号类型,它们实际上并不能保证是标准整数类型的有符号和无符号版本.因此,此代码是否违反严格别名是特定于实现的.违反严格别名的代码具有未定义的行为.以下确实违反了严格的别名,只要 randomUintNumber 中的位模式是 long long 值的有效表示,则可以:

This isn't quite guaranteed to work, because although where they exist int64_t and uint64_t are guaranteed to be a signed type and an unsigned type of the same size, they aren't actually guaranteed to be the signed and unsigned versions of a standard integer type. So it is implementation-specific whether or not this code violates strict aliasing. Code that violates strict aliasing has undefined behavior. The following does not violate strict aliasing, and is OK provided that the bit pattern in randomUintNumber is a valid representation of a value of long long:

unsigned long long x = 0;
const long long y = reinterpret_cast<long long &>(x);

所以在 int64_tuint64_tlong longunsigned long long 的 typedef 的实现中,那么我的reinterpret_cast 没问题.与实现定义的超出范围值到有符号类型的转换一样,您会期望实现的明智之举是让它们对应有符号/无符号类型.因此,就像 static_cast 和隐式转换一样,您希望它可以在任何合理的实现中工作,但实际上并不能保证.

So on implementations where int64_t and uint64_t are typedefs for long long and unsigned long long, then my reinterpret_cast is OK. And as with the implementation-defined conversion of out-of-range values to signed types, you would expect that the sensible thing for implementations to do is to make them corresponding signed/unsigned types. So like the static_cast and the implicit conversion, you expect it to work in any sensible implementation but it is not actually guaranteed.

这篇关于为什么我不能将 uint 重新解释为 int?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆