C和C标准规定,在相同等级的有符号和无符号整数之间的二进制运算中,有符号整数被转换为无符号整数 . 由此引起的SO有很多问题......我们称之为奇怪的行为:unsigned to signed conversion,C++ Implicit Conversion (Signed + Unsigned),A warning - comparison between signed and unsigned integer expressions,% (mod) with mixed signedness等 .
但是这些都没有给出任何理由,为什么标准是这样的,而不是倾向于签署的注册 . 我确实找到了一位自封的大师,他说这也是一个推理:http://embeddedgurus.com/stack-overflow/2009/08/a-tutorial-on-signed-and-unsigned-integers/ .
查看我自己的代码,无论我将有符号和无符号整数组合在一起,我总是需要从unsigned转换为signed . 有些地方没关系,但我没有找到一个代码示例,将有符号整数转换为unsigned是有意义的 .
什么情况下铸造到无符号的正确的事情呢?为什么标准是这样的?
2 回答
如果无法表示值,则从无符号转换为签名会导致实现定义的行为 . 从有符号到无符号的转换总是以无符号的bitsize的幂为模2,因此它总是被很好地定义 .
如果每个可能的无符号值都可以在签名类型中表示,则标准转换为签名类型 . 否则,选择无符号类型 . 这保证了转换始终是明确定义的 .
注意事项
如评论中所示,C的转换算法是从C继承的,以保持兼容性,这在技术上是C语言的原因 .
有人建议,标准中定义签名到无符号转换而不是无符号转换为签名转换的决定在某种程度上是任意的,而另一个可能的决定是对称的 . 但是,可能的转换不是对称的 .
在标准所考虑的两个非二进制补码表示中,n位有符号表示可以仅表示2n-1个值,而n位无符号表示可以表示2n个值 . 因此,有符号到无符号的转换是无损的,可以反转(尽管永远不会产生一个无符号值) . 另一方面,无符号到符号的转换必须将两个不同的无符号值折叠到同一个带符号的结果上 .
在评论中,提出了公式
sint = uint > sint_max ? uint - uint_max : uint
. 这将合并值uint_max
和0;两者都映射到0. 's a little weird even for non-2s-complement representations, but for 2' s补码's unnecessary and, worse, it requires the compiler to emit code to laboriously compute this unnecessary conflation. By contrast the standard'签名到无符号转换是无损的,在通常情况下(2的补码架构)它是无操作的 .这是一个半答案,因为我不太了解委员会的推理 .
来自C90委员会的理由文件:https://www.lysator.liu.se/c/rat/c2.html#3-2-1-1
......显然也是为了匹配任何运算符的两个操作数而进行的转换 . 它继续:
然后,它指定了解释模糊的情况,并指出:
和:
因此,他们认为
int + unsigned
的情况是不受欢迎的情况,并选择char
和short
的转换规则,尽可能少地产生这些情况, even though most compilers at the time followed a different approach. 如果我理解正确,那么这个选择迫使他们遵循当前选择int + unsigned
产生一个unsigned
操作 .我仍然觉得这一切真的很奇怪 .