首页 文章

为什么C标准指定有符号整数在具有混合签名的二进制操作中转换为无符号整数?

提问于
浏览
8

C和C标准规定,在相同等级的有符号和无符号整数之间的二进制运算中,有符号整数被转换为无符号整数 . 由此引起的SO有很多问题......我们称之为奇怪的行为:unsigned to signed conversionC++ 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 回答

  • 9

    如果无法表示值,则从无符号转换为签名会导致实现定义的行为 . 从有符号到无符号的转换总是以无符号的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的补码架构)它是无操作的 .

  • 1

    这是一个半答案,因为我不太了解委员会的推理 .

    来自C90委员会的理由文件:https://www.lysator.liu.se/c/rat/c2.html#3-2-1-1

    自K&R出版以来,C在整体推广规则演变中的实施发生了严重分歧 . 实施分为两个主要阵营,其特征可以是无符号保留和保值 . 这些方法之间的区别在于对unsigned char和unsigned short的处理,当通过整体促销扩大时,但决定对常量的类型也有影响(见§3.1.3.2) .

    ......显然也是为了匹配任何运算符的两个操作数而进行的转换 . 它继续:

    在绝大多数情况下,两种方案都给出了相同的答案,并且在具有二进制补码算法的实现中以及在有符号溢出的安静环绕中,即在大多数当前实现中,两者都给出了相同的有效结果 .

    然后,它指定了解释模糊的情况,并指出:

    必须对结果进行有问题的签名,因为可以对签名或未签名的解释进行陈述 . 只要unsigned int在运算符中面对signed int并且signed int具有负值,就会出现完全相同的歧义 . (在解决这种对抗的模糊性时,这两种方案都没有做得更好,或者更糟糕 . )突然之间,负面符号int成为一个非常大的无符号整数,这可能是令人惊讶的 - 或者它可能正是所期望的知识渊博的程序员 . 当然,通过明智地使用演员阵容可以避免所有这些含糊之处 .

    和:

    无符号保留规则极大地增加了签名的unsigned int面临的情况的数量int产生可疑的签名结果,而值保留规则最小化这种对抗 . 因此,对于新手或不警惕的程序员来说,保值规则被认为更安全 . 经过多次讨论后,委员会决定支持保值规则,尽管UNIX C编译器已朝着无符号保留的方向发展 .

    因此,他们认为 int + unsigned 的情况是不受欢迎的情况,并选择 charshort 的转换规则,尽可能少地产生这些情况, even though most compilers at the time followed a different approach. 如果我理解正确,那么这个选择迫使他们遵循当前选择 int + unsigned 产生一个 unsigned 操作 .

    我仍然觉得这一切真的很奇怪 .

相关问题