为什么我不能将uint重新解释为int?

时间:2023-02-07 02:57:26

Here's what I want to do:

下面是我想做的:

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

const int64_t randomIntNumber = reinterpret_cast (randomUintNumber);

Where randomUintNumber is of type uint64_t.

其中randomUintNumber类型为uint64_t。

The error is (MSVC 2010):

误差为(MSVC 2010):

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

错误C2440:“reinterpret_cast”:不能将“const uint64_t”转换为“int64_t”1>转换为有效的标准转换,可以隐式地执行,也可以使用static_cast、c style cast或泛型cast

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

为什么它不能编译?这两种类型都有相同的比特长度,这不是reviewt_cast的目的吗?

6 个解决方案

#1


19  

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].

因为reinterpret_cast不是这个意思。所有允许的reinterpret_cast转换都包含指针或引用,但整数或枚举类型可以重新解释为自身。这在标准[exp . reinterpretation .cast]中都有定义。

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

我不确定您想要实现什么,但是如果您希望随机数具有与randomUintNumber相同的值,那么就这样做

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

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.

如果随机数小于263,则cast的结果与输入的值相同。否则,结果是实现定义的,但是我希望所有已知的int64_t实现都将定义它来做一件显而易见的事情:结果等同于输入模块264。


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

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

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

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.

因为int64_t保证使用2的补表示,所以您希望实现定义static_cast对于uint64_t的范围外的值具有与此相同的结果。但在AFAIK标准中并没有保证。

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:

如果您需要解决这个问题,并且您不相信实现是明智的,将out- range未签名的值转换为已签名的类型,那么如下所示:

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

or equivalently:

或者说:

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

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:

这并不能保证有效,因为尽管存在int64_t和uint64_t的地方被保证是一个有符号类型和一个大小相同的无符号类型,但它们实际上并不能保证是标准整数类型的有符号和无符号版本。因此,无论这段代码是否违反了严格的别名,它都是特定于实现的。违反严格别名的代码具有未定义的行为。下面的内容并不违反严格的混叠,并且可以假设随机数字中的位模式是长时间值的有效表示:

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

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.

因此,在实现中,int64_t和uint64_t是long long long和unsigned long的类型defs,那么reinterpret_cast就可以了。与实现定义的范围外值到签名类型的转换一样,您可能希望实现要做的明智的事情是使它们成为相应的签名/无签名类型。就像static_cast和隐式转换一样,您期望它在任何合理的实现中都能工作,但实际上并没有得到保证。

#2


3  

No, it is not. reinterpret_cast is mostly intended to reinterpret an existing bit of storage as a different type than it is. A lot of these interpretations is implementation dependent, and the standard lists a specific (rather long to quote here) list of things that can be done with a reinterpret_cast (mostly casting between different pointer/reference types), but says:

不,它不是。reinterpretation t_cast主要是为了将现有的存储位重新解释为不同的类型。很多这样的解释都是依赖于实现的,而标准列出了一个特定的(相当长的引用)列表,可以通过re解释性的转换(主要是在不同的指针/引用类型之间进行转换)来完成,但是说:

No other conversion can be performed explicitly using reinterpret_cast.

没有其他的转换可以使用re解释t_cast显式地执行。

In your case, you probably want a conversion of types, not a reinterpretation of existing storage. Use static_cast for this purpose.

在您的示例中,您可能希望转换类型,而不是重新解释现有存储。为此使用static_cast。

#3


2  

Use static_cast in these cases. I suppose the language designers in all their wisdom decided that it's not considered "unsafe enough" to warrant a reinterpret_cast.

在这些情况下使用static_cast。我猜想语言设计者们在他们的智慧中认为它还不够“不安全”,不值得重新解释。

#4


1  

From C++11 Standard(N3376) 5.2.10.1:

从c++标准(N3376)5.2.10.1:11

Conversions that can be performed explicitly using reinterpret_cast are listed below. No other conversion can be performed explicitly using reinterpret_cast.

下面列出了可以使用reinterpret_cast显式执行的转换。没有其他的转换可以使用re解释t_cast显式地执行。

The only conversion from integral type to integral type allowed is infact if the types are identical.

如果类型相同,则允许从整型转换为整型。

Others involve pointers.

其他涉及指针。

#5


1  

reinterpret_cast is used for reinterpreting the storage of the object as a different object. If you don't want to go through standard wording, you can find all that reinterpret_cast can do here. Generally you can remember you have to work with pointer types.

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

So, if you really want to reinterpret the bits used for your uint64_t as int64_t, then do this:

所以,如果你真的想把uint64_t的位重新解释为int64_t,那么就这么做:

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

However if you just want to convert the object, preserving its value if possible ... just do what the compiler suggests and use static_cast instead.

但是,如果您只是想要转换对象,如果可能的话,保留它的值……只需按照编译器的建议使用static_cast。

#6


0  

Why doesn't it compile?

为什么它不能编译?

Because neither type is a pointer.

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

both types have the same bit length,

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

Why would that matter? If they were pointers, maybe it would matter that they pointed to things of the same size, but they're not pointers.

为什么这有关系吗?如果它们是指针,那么它们指向相同大小的东西可能很重要,但它们不是指针。

isn't it what reinterpret_cast is intended for?

reinterpretation t_cast不是这样的吗?

No, reinterpret_cast is for pointer casts. You could do what you want by putting an & inside the cast and a * outside it. That's what reinterpret cast is for.

不,reinterpretation t_cast是指针类型的类型。你可以把一个&放在石膏里面,把一个*放在外面。这就是reinterpretation的目的。

#1


19  

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].

因为reinterpret_cast不是这个意思。所有允许的reinterpret_cast转换都包含指针或引用,但整数或枚举类型可以重新解释为自身。这在标准[exp . reinterpretation .cast]中都有定义。

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

我不确定您想要实现什么,但是如果您希望随机数具有与randomUintNumber相同的值,那么就这样做

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

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.

如果随机数小于263,则cast的结果与输入的值相同。否则,结果是实现定义的,但是我希望所有已知的int64_t实现都将定义它来做一件显而易见的事情:结果等同于输入模块264。


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

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

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

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.

因为int64_t保证使用2的补表示,所以您希望实现定义static_cast对于uint64_t的范围外的值具有与此相同的结果。但在AFAIK标准中并没有保证。

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:

如果您需要解决这个问题,并且您不相信实现是明智的,将out- range未签名的值转换为已签名的类型,那么如下所示:

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

or equivalently:

或者说:

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

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:

这并不能保证有效,因为尽管存在int64_t和uint64_t的地方被保证是一个有符号类型和一个大小相同的无符号类型,但它们实际上并不能保证是标准整数类型的有符号和无符号版本。因此,无论这段代码是否违反了严格的别名,它都是特定于实现的。违反严格别名的代码具有未定义的行为。下面的内容并不违反严格的混叠,并且可以假设随机数字中的位模式是长时间值的有效表示:

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

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.

因此,在实现中,int64_t和uint64_t是long long long和unsigned long的类型defs,那么reinterpret_cast就可以了。与实现定义的范围外值到签名类型的转换一样,您可能希望实现要做的明智的事情是使它们成为相应的签名/无签名类型。就像static_cast和隐式转换一样,您期望它在任何合理的实现中都能工作,但实际上并没有得到保证。

#2


3  

No, it is not. reinterpret_cast is mostly intended to reinterpret an existing bit of storage as a different type than it is. A lot of these interpretations is implementation dependent, and the standard lists a specific (rather long to quote here) list of things that can be done with a reinterpret_cast (mostly casting between different pointer/reference types), but says:

不,它不是。reinterpretation t_cast主要是为了将现有的存储位重新解释为不同的类型。很多这样的解释都是依赖于实现的,而标准列出了一个特定的(相当长的引用)列表,可以通过re解释性的转换(主要是在不同的指针/引用类型之间进行转换)来完成,但是说:

No other conversion can be performed explicitly using reinterpret_cast.

没有其他的转换可以使用re解释t_cast显式地执行。

In your case, you probably want a conversion of types, not a reinterpretation of existing storage. Use static_cast for this purpose.

在您的示例中,您可能希望转换类型,而不是重新解释现有存储。为此使用static_cast。

#3


2  

Use static_cast in these cases. I suppose the language designers in all their wisdom decided that it's not considered "unsafe enough" to warrant a reinterpret_cast.

在这些情况下使用static_cast。我猜想语言设计者们在他们的智慧中认为它还不够“不安全”,不值得重新解释。

#4


1  

From C++11 Standard(N3376) 5.2.10.1:

从c++标准(N3376)5.2.10.1:11

Conversions that can be performed explicitly using reinterpret_cast are listed below. No other conversion can be performed explicitly using reinterpret_cast.

下面列出了可以使用reinterpret_cast显式执行的转换。没有其他的转换可以使用re解释t_cast显式地执行。

The only conversion from integral type to integral type allowed is infact if the types are identical.

如果类型相同,则允许从整型转换为整型。

Others involve pointers.

其他涉及指针。

#5


1  

reinterpret_cast is used for reinterpreting the storage of the object as a different object. If you don't want to go through standard wording, you can find all that reinterpret_cast can do here. Generally you can remember you have to work with pointer types.

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

So, if you really want to reinterpret the bits used for your uint64_t as int64_t, then do this:

所以,如果你真的想把uint64_t的位重新解释为int64_t,那么就这么做:

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

However if you just want to convert the object, preserving its value if possible ... just do what the compiler suggests and use static_cast instead.

但是,如果您只是想要转换对象,如果可能的话,保留它的值……只需按照编译器的建议使用static_cast。

#6


0  

Why doesn't it compile?

为什么它不能编译?

Because neither type is a pointer.

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

both types have the same bit length,

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

Why would that matter? If they were pointers, maybe it would matter that they pointed to things of the same size, but they're not pointers.

为什么这有关系吗?如果它们是指针,那么它们指向相同大小的东西可能很重要,但它们不是指针。

isn't it what reinterpret_cast is intended for?

reinterpretation t_cast不是这样的吗?

No, reinterpret_cast is for pointer casts. You could do what you want by putting an & inside the cast and a * outside it. That's what reinterpret cast is for.

不,reinterpretation t_cast是指针类型的类型。你可以把一个&放在石膏里面,把一个*放在外面。这就是reinterpretation的目的。