为了账号安全,请及时绑定邮箱和手机立即绑定

无符号整数减法是否定义了行为?

无符号整数减法是否定义了行为?

C
慕尼黑8549860 2019-08-16 16:47:01
无符号整数减法是否定义了行为?我遇到的代码来自一个似乎认为在结果为负时从另一个相同类型的整数中减去无符号整数的问题。因此,即使它恰好适用于大多数体系结构,这样的代码也是不正确的。unsigned int To, Tf;To = getcounter();while (1) {     Tf = getcounter();     if ((Tf-To) >= TIME_LIMIT) {         break;     } }这是我能找到的C标准中唯一含糊不清的引用。涉及无符号操作数的计算永远不会过度流动,因为无法用结果无符号整数类型表示的结果将以比结果类型可以表示的最大值大1的数量为模。我想人们可以接受这个引用来表示当右操作数较大时,操作被调整为在模数截断数字的上下文中有意义。即0x0000 - 0x0001 == 0x 1 0000 - 0x0001 == 0xFFFF而不是使用依赖于实现的签名语义:0x0000 - 0x0001 ==(无符号)(0 + -1)==(0xFFFF但也是0xFFFE或0x8001)哪种或哪种解释是对的?是否定义了?
查看完整描述

3 回答

?
烙印99

TA贡献1829条经验 获得超13个赞

在无符号类型中生成负数的减法结果是明确定义的:

  1. [...]涉及无符号操作数的计算永远不会溢出,因为无法由结果无符号整数类型表示的结果以比模式结果类型可以表示的最大值大1的数量减少。(ISO / IEC 9899:1999(E)§6.2.5/ 9)

如您所见,(unsigned)0 - (unsigned)1等于-1模UINT_MAX + 1,或换句话说,UINT_MAX。

请注意,虽然它确实说“涉及无符号操作数的计算永远不会溢出”,这可能导致您认为它仅适用于超出上限,但这被表示为句子的实际绑定部分的动机:“a无法用结果无符号整数类型表示的结果以模数减少为模数,该数字大于可由结果类型表示的最大值。该短语不限于类型上限的溢出,并且同样适用于太低而无法表示的值。


查看完整回答
反对 回复 2019-08-16
?
qq_花开花谢_0

TA贡献1835条经验 获得超7个赞


使用无符号类型时,会发生模运算(也称为“环绕”行为)。要理解这种模块化算法,只需看看这些时钟:

https://img1.sycdn.imooc.com//5d566db00001701002200096.png

9 + 4 = 1(13 mod 12),所以对另一个方向是:1 - 4 = 9(-3 mod 12)。使用无符号类型时应用相同的原则。如果结果类型是unsigned,则进行模运算。


现在看一下将结果存储为以下操作unsigned int:


unsigned int five = 5, seven = 7;

unsigned int a = five - seven;      // a = (-2 % 2^32) = 4294967294 


int one = 1, six = 6;

unsigned int b = one - six;         // b = (-5 % 2^32) = 4294967291

当您想确保结果是signed,然后将其存储到signed变量或转换为signed。如果想要获得数字之间的差异并确保不应用模运算,那么您应该考虑使用以下abs()定义的函数stdlib.h:


int c = five - seven;       // c = -2

int d = abs(five - seven);  // d =  2

要非常小心,特别是在写条件时,因为:


if (abs(five - seven) < seven)  // = if (2 < 7)

    // ...


if (five - seven < -1)          // = if (-2 < -1)

    // ...


if (one - six < 1)              // = if (-5 < 1)

    // ...


if ((int)(five - seven) < 1)    // = if (-2 < 1)

    // ...


if (five - seven < 1)   // = if ((unsigned int)-2 < 1) = if (4294967294 < 1)

    // ...


if (one - six < five)   // = if ((unsigned int)-5 < 5) = if (4294967291 < 5)

    // ...


查看完整回答
反对 回复 2019-08-16
?
繁星coding

TA贡献1797条经验 获得超4个赞

那么,第一种解释是正确的。但是,你在这种情况下对“签名语义”的推理是错误的。

再次,你的第一个解释是正确的。无符号算术遵循模运算的规则,这意味着对32位无符号类型0x0000 - 0x0001求值0xFFFF

但是,第二种解释(基于“签名语义”的解释)也需要产生相同的结果。即使您0 - 1在签名类型的域中进行评估并获得-1作为中间结果,-1仍然需要0xFFFF在以后将其转换为无符号类型时生成。即使某些平台对有符号整数使用奇异表示(1的补码,有符号幅度),在将有符号整数值转换为无符号整数值时,仍需要使用该平台来应用模运算规则。

例如,这个评估

signed int a = 0, b = 1;unsigned int c = a - b;

仍保证生产UINT_MAXc,即使该平台采用异国情调的代表符号整数。


查看完整回答
反对 回复 2019-08-16
  • 3 回答
  • 0 关注
  • 987 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信