没有符合要求的转换具有相同大小的signed / unsigned的方式 [英] No compliant way to convert signed/unsigned of same size

查看:162
本文介绍了没有符合要求的转换具有相同大小的signed / unsigned的方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我担心我可能会遗漏一些微不足道的东西,但是如果您想保留原始的未签名值,则似乎没有实际安全的方式转换/从一个签名类型。

I fear I may be missing something trivial, but it appears there is no actual safe way to convert to/from a signed type if you wish to retain the original unsigned value.

在reinterpret_cast中,5.2.10没有列出整数到整数转换,因此它没有定义(和static_cast没有定义额外的转换)。对整数转换4.7.3基本上说,大的未签名的转换将是实现定义的(因此不可移植)。

On reinterpret_cast, 5.2.10 does not list an integer to integer conversion, thus it is not defined (and static_cast defines no additional conversion). On integral conversions 4.7.3 basically says conversion of a large unsigned will be implementation defined (thus not portable).

这似乎是限制,因为我们知道, uint64_t 应在任何硬件上安全地转换为 int64_t 并返回而不更改值。加上标准布局类型的规则实际上保证安全转换,如果两个类型之间 memcpy 而不是assign。

This seems limiting since we know, for example, that a uint64_t should, on any hardware, be safely convertible to a int64_t and back without change in value. Plus the rules on standard layout types actually guarantee safe conversion if we were to memcpy between the two types instead of assign.

我是否正确?有没有合理的理由,为什么在整数类型足够大小之间不能 reinterpret_cast

Am I correct? Is there a legitimate reason why one cannot reinterpret_cast between integral types sufficient size?

澄清:无符号的有符号版本无法保证一个值,但它只是我考虑的往返(unsigned => signed => unsigned)

Clarification: Definitely the signed version of the unsigned is not guaranteed a value, but it is only the round-trip that I am considering (unsigned => signed => unsigned)

UPDATE :仔细观察答案并交叉检查标准,我相信 memcpy 实际上不能保证工作,因为它没有声明这两种类型是布局兼容,也不是字符类型。进一步更新,挖入C标准这个memcpy应该工作,因为目标是足够大,它复制的字节。

UPDATE: Looking closely at the answers and cross-checking the standard, I believe the memcpy is not actually guaranteed to work, as nowhere does it state that the two types are layout compatible, and neither are char types. Further update, digging into the C-standard this memcpy should work, as the sizeof the target is large enough and it copies the bytes.

ANSWER :似乎没有技术原因可以拒绝reinterpret_cast执行此转换。对于这些固定大小的整数类型, memcpy 可以保证工作,实际上只要中间体可以表示所有位模式,任何中间类型都可以使用(float可能是危险的因为可能存在陷阱模式)。一般来说,你不能在任何标准布局类型之间memcpy,它们必须是兼容或char类型。

ANSWER: There appears to be no technical reason why reinterpret_cast was not allowed to perform this conversion. For these fixed size integer types a memcpy is guaranteed to work, and indeed so long as the intermediate can represent all bit-patterns any intermediate type can be used (float's can be dangerous as there may be trap patterns). In general you can't memcpy between any standard layout types, they must be compatible or char type. Here the ints are special since they have additional guarantees.

推荐答案

正如你所指出的,memcpy是安全的:

As you point out, memcpy is safe:

uint64_t a = 1ull<<63;
int64_t b;
memcpy(&b,&a,sizeof a);

值为b仍然是实现定义的,因为C ++不需要二的补码表示, 但是转换回来会给你原来的值。

The value is b is still implementation defined since C++ does not require a two's complement representation, but converting it back will give you the original value.

正如Bo Persson指出的,int64_t将是二进制补码。因此,memcpy应该产生一个有符号的值,其中简单的积分转换回到无符号类型被很好地定义为原始的未签名值。

As Bo Persson points out int64_t will be two's complement. Therefore the memcpy should result in a signed value for which the simple integral conversion back to the unsigned type is well defined to be the original unsigned value.

uint64_t c = b;
assert( a == c );

此外,您可以实施自己的signed_cast因为这些不限于intN_t类型):

Also, you can implement your own 'signed_cast' to make conversions easy (I don't take advantage of the two's complement thing since these aren't limited to the intN_t types):

template<typename T>
typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value,T>::type
signed_cast(typename std::make_unsigned<T>::type v) {
    T s;
    std::memcpy(&s,&v,sizeof v);
    return s;
}

template<typename T>
typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value,T>::type
signed_cast(typename std::make_signed<T>::type v) {
    T s;
    std::memcpy(&s,&v,sizeof v);
    return s;
}

这篇关于没有符合要求的转换具有相同大小的signed / unsigned的方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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