通过减法签名无符号

时间:2017-09-13 19:58:22

标签: c

我最近决定实现这一目标并阅读一系列计算机科学书籍,以便更好地为未来做好准备。

目前我正在阅读将有符号转换为无符号小数。我理解大多数人(希望最终变得容易),但是对于以下(32位)的努力:

-2147483647-1U< -2147483647

根据这本书,这评估为真。有一点关于这一点,我仍然在努力,因为我不知道为什么它评估这个。

根据我的理解,我知道在这个计算中它们都被转换为无符号值,因为第一个数字被转换为无符号。因此,减法后第一个数字是-2147483648,然后转换为无符号,或者在减法之前进行无符号转换?

对于冗长的帖子感到抱歉,只是试着理解这一点。

谢谢!

4 个答案:

答案 0 :(得分:6)

  

减法后的第一个数字是-2147483648然后   转换为无符号,或先执行无符号转换   减法?

后者是真的。根据{{​​3}}:

  

...否则,如果具有无符号整数类型的操作数具有等级   那么,大于或等于另一个操作数的类型的等级   带有符号整数类型的操作数转换为   具有无符号整数类型的操作数。

因此,所有操作数,用于减法和比较的操作数都转换为无符号。

P.S。为了完整起见,转化程序在C11 Standard "6.3.1.8 Usual arithmetic conversions"中说明:

  

...如果新类型是无符号的,则转换为   重复加或减一个以上的最大值   可以用新类型表示,直到值在范围内   新类型。

P.P.S。答案是假设int为32位长。如果小于该值,那么负常数-2147483647将具有类型long,其等级高于unsigned int,即1U,然后上述将不适用,不会进行转换(感谢@Olaf指出)。

答案 1 :(得分:5)

  

减法后第一个数字是-2147483648

不完全。首先转换为unsigned。对于混合int/unsigned数学,int将转换为unsigned

减去2个unsigned会产生unsigned,而unsigned永远不会消极。

假设32位或更宽unsigned/int

-2147483647-1U int 减去无符号,因此-2147483647会转换为unsigned 2147483649,差异为{{1} }}。现在,无符号unsigned 2147483648进行比较,因此int会转换为int。左边小于右边,结果是真的。

[编辑]

假设窄于32位unsigned 2147483649,但unsigned/int使用常见的2&补码编码。经常在2017年的嵌入式8/16位处理器中看到。

long减去较窄的无符号,因此-2147483647-1U仍为-2147483647long为转换为1U,差异为int 1。现在,long -2147483648long进行比较。左边小于右边,结果是真的。

答案 2 :(得分:2)

两者都会提升为未签名且-2147483647-1U == 0x8000000(unsigned)-2147483647 == 0x80000001

0x8000000 < 0x8000001true

与仅签名

相同
-2147483647-1 == `-2147483648`
-2147483648 < -2147483647

答案 3 :(得分:1)

这真的很简单。 根据{{​​3}},如果int在操作中遇到unsigned int,则操作数都会转换为unsigned int

形式化为6.3.1.8 Usual arithmetic conversions的转换确实描述了自然签名/无符号重新解释如何在repeatedly adding or subtracting one more than maximum value that can be represented in the new type算术中工作(最常见的方式,但不是唯一的方式,表示硬件中的有符号整数)。

对32位有符号数的

two's complement算法的工作原理如下:

  • 最高位,如果设置,则代表-2 ^ 31
  • 其余的代表自己
因此,{p> -21474836472^31+1 == 0b10000000000000000000000000000001。 现在,由于它涉及1U0b00000000000000000000000000000001)的减法操作,您应该通过重复添加或减去uint32_t将其转换为UINT32_MAX+1 == 2^32数字,这会在溢出后生成在相同的二进制表示中(我想这些规则是为了在2的补码(最常见)平台上直接重新解释这些位),从中减去1U将直接产生 0b10000000000000000000000000000000 == 2^31,小于2^31+1