在reinterpret_cast上,5.2.10没有列出整数到整数的转换,因此没有定义(而static_cast定义没有额外的转换).关于积分转换4.7.3基本上说大型无符号的转换将是实现定义的(因此不可移植).
这似乎有限,因为我们知道,例如,uint64_t应该在任何硬件上安全地转换为int64_t并返回而不改变值.另外,标准布局类型的规则实际上保证了安全转换,如果我们在两种类型之间memcpy而不是assign.
我对么?有没有合理的理由说明为什么不能在整数类型之间重新解释广播?
澄清:肯定签名版本的无符号不保证值,但它只是我考虑的往返(unsigned => signed => unsigned)
更新:仔细查看答案并交叉检查标准,我相信memcpy实际上并不能保证工作,因为它没有说明这两种类型是布局兼容的,也不是char类型.进一步更新,挖掘C标准这个memcpy应该工作,因为目标的大小足够大并且它复制字节.
答案:似乎没有技术上的理由说明为什么不允许reinterpret_cast执行此转换.对于这些固定大小的整数类型,memcpy保证可以工作,实际上只要中间可以表示所有的位模式,任何中间类型都可以使用(浮点数可能很危险,因为可能存在陷阱模式).通常,您不能在任何标准布局类型之间进行memcpy,它们必须是兼容的或char类型.这里的注册是特殊的,因为它们有额外的保证.
解决方法
uint64_t a = 1ull<<63; int64_t b; memcpy(&b,&a,sizeof a);
值b仍然是实现定义的,因为C不需要二进制补码表示,但是将其转换回来将给出原始值.
正如Bo PeRSSon所指出的,int64_t将是两个补码.因此,memcpy应该产生一个有符号值,对于该有符号值,简单的积分转换回无符号类型被很好地定义为原始的无符号值.
uint64_t c = b; assert( a == c );
此外,您可以实现自己的’signed_cast’以简化转换(我不利用这两个补码,因为它们不仅限于intN_t类型):
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,sizeof v); return s; }