猿问

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

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

我遇到的代码来自一个似乎认为在结果为负时从另一个相同类型的整数中减去无符号整数的问题。因此,即使它恰好适用于大多数体系结构,这样的代码也是不正确的。

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)

哪种或哪种解释是对的?是否定义了?


慕尼黑8549860
浏览 988回答 3
3回答

烙印99

在无符号类型中生成负数的减法结果是明确定义的:[...]涉及无符号操作数的计算永远不会溢出,因为无法由结果无符号整数类型表示的结果以比模式结果类型可以表示的最大值大1的数量减少。(ISO / IEC 9899:1999(E)§6.2.5/ 9)如您所见,(unsigned)0 - (unsigned)1等于-1模UINT_MAX + 1,或换句话说,UINT_MAX。请注意,虽然它确实说“涉及无符号操作数的计算永远不会溢出”,这可能导致您认为它仅适用于超出上限,但这被表示为句子的实际绑定部分的动机:“a无法用结果无符号整数类型表示的结果以模数减少为模数,该数字大于可由结果类型表示的最大值。该短语不限于类型上限的溢出,并且同样适用于太低而无法表示的值。

qq_花开花谢_0

使用无符号类型时,会发生模运算(也称为“环绕”行为)。要理解这种模块化算法,只需看看这些时钟: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;&nbsp; &nbsp; &nbsp; // a = (-2 % 2^32) = 4294967294&nbsp;int one = 1, six = 6;unsigned int b = one - six;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// b = (-5 % 2^32) = 4294967291当您想确保结果是signed,然后将其存储到signed变量或转换为signed。如果想要获得数字之间的差异并确保不应用模运算,那么您应该考虑使用以下abs()定义的函数stdlib.h:int c = five - seven;&nbsp; &nbsp; &nbsp; &nbsp;// c = -2int d = abs(five - seven);&nbsp; // d =&nbsp; 2要非常小心,特别是在写条件时,因为:if (abs(five - seven) < seven)&nbsp; // = if (2 < 7)&nbsp; &nbsp; // ...if (five - seven < -1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // = if (-2 < -1)&nbsp; &nbsp; // ...if (one - six < 1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // = if (-5 < 1)&nbsp; &nbsp; // ...if ((int)(five - seven) < 1)&nbsp; &nbsp; // = if (-2 < 1)&nbsp; &nbsp; // ...但if (five - seven < 1)&nbsp; &nbsp;// = if ((unsigned int)-2 < 1) = if (4294967294 < 1)&nbsp; &nbsp; // ...if (one - six < five)&nbsp; &nbsp;// = if ((unsigned int)-5 < 5) = if (4294967291 < 5)&nbsp; &nbsp; // ...

繁星coding

那么,第一种解释是正确的。但是,你在这种情况下对“签名语义”的推理是错误的。再次,你的第一个解释是正确的。无符号算术遵循模运算的规则,这意味着对32位无符号类型0x0000 - 0x0001求值0xFFFF。但是,第二种解释(基于“签名语义”的解释)也需要产生相同的结果。即使您0 - 1在签名类型的域中进行评估并获得-1作为中间结果,-1仍然需要0xFFFF在以后将其转换为无符号类型时生成。即使某些平台对有符号整数使用奇异表示(1的补码,有符号幅度),在将有符号整数值转换为无符号整数值时,仍需要使用该平台来应用模运算规则。例如,这个评估signed&nbsp;int&nbsp;a&nbsp;=&nbsp;0,&nbsp;b&nbsp;=&nbsp;1;unsigned&nbsp;int&nbsp;c&nbsp;=&nbsp;a&nbsp;-&nbsp;b;仍保证生产UINT_MAX中c,即使该平台采用异国情调的代表符号整数。
随时随地看视频慕课网APP
我要回答