24

这是我想要做的:

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

其中 randomUintNumber 类型为uint64_t

错误是(MSVC 2010):

错误 C2440: 'reinterpret_cast' : 无法从 'const uint64_t' 转换为 'int64_t' 1> 转换是有效的标准转换,可以隐式执行或使用 static_cast、C 样式转换或函数样式转换

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

4

7 回答 7

31

因为那不是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如果小于 2 63,则强制转换的结果与输入具有相同的值。否则结果是实现定义的,但我希望所有已知的实现int64_t都会定义它来做显而易见的事情:结果相当于输入模 2 64


如果你想randomIntNumber拥有与 相同的位模式randomUintNumber,那么你可以这样做:

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

由于int64_t保证使用二进制补码表示,因此您希望实现定义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保证是相同大小的有符号类型和无符号类型,但它们实际上并不能保证是标准整数类型的有符号和无符号版本。因此,此代码是否违反严格别名是特定于实现的。违反严格别名的代码具有未定义的行为。以下不违反严格的别名,只要位模式 inrandomUintNumber是 的值的有效表示,就可以了long long

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

因此,在and 是int64_tanduint64_t的 typedef 的实现long longunsigned long long,我reinterpret_cast的就可以了。与将超出范围的值转换为有符号类型的实现定义的转换一样,您会期望实现要做的明智的事情是使它们对应于有符号/无符号类型。因此,就像static_cast隐式转换一样,您希望它可以在任何合理的实现中工作,但实际上并不能保证。

于 2013-01-31T10:20:29.470 回答
7

static_cast在这些情况下使用。我想语言设计者在他们所有的智慧中都认为它不被认为“足够不安全”来保证reinterpret_cast.

于 2013-01-31T10:14:56.973 回答
3

不它不是。reinterpret_cast主要是为了将现有的存储位重新解释为与它不同的类型。很多这些解释是依赖于实现的,标准列出了一个特定的(在这里引用很长)可以用reinterpret_cast(主要是在不同的指针/引用类型之间进行转换)完成的事情的列表,但是说:

无法使用 reinterpret_cast 显式执行其他转换。

在您的情况下,您可能想要转换类型,而不是重新解释现有存储。用于static_cast此目的。

于 2013-01-31T10:19:07.093 回答
2

来自 C++11 Standard(N3376) 5.2.10.1本文档,第 101 页

下面列出了可以使用 reinterpret_cast 显式执行的转换。无法使用 reinterpret_cast 显式执行其他转换。

实际上,如果类型相同,则允许从整数类型到整数类型的唯一转换。

其他涉及指针。

于 2013-01-31T10:23:14.307 回答
1

reinterpret_cast用于将对象的存储重新解释为不同的对象。如果您不想通过标准措辞,您可以在这里reinterpret_cast找到所有可以做的事情。通常你可以记住你必须使用指针类型。

因此,如果您真的想重新解释用于uint64_tas的位,请int64_t执行以下操作:

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

但是,如果您只想转换对象,请尽可能保留其值……只需按照编译器的建议进行操作并static_cast改用即可。

于 2013-01-31T10:25:13.893 回答
1

为什么不编译?

因为这两种类型都不是指针。

两种类型具有相同的位长,

这有什么关系?如果它们是指针,也许它们指向相同大小的东西会很重要,但它们不是指针。

这不是 reinterpret_cast 的用途吗?

不,reinterpret_cast用于指针强制转换。&您可以通过在演员表内部和外部放入演员表来做您想做的*事情。这就是重新解释演员阵容的目的。

于 2013-01-31T10:21:32.130 回答
1

用 重新解释位模式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 << "\n\n";
    std::cout << "randomUintNumber: " << randomUintNumber << "\n\n";
    
    // 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 ...\n\n";
    
    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
于 2020-08-06T09:47:03.187 回答