3 回答
TA贡献1829条经验 获得超13个赞
在无符号类型中生成负数的减法结果是明确定义的:
[...]涉及无符号操作数的计算永远不会溢出,因为无法由结果无符号整数类型表示的结果以比模式结果类型可以表示的最大值大1的数量减少。(ISO / IEC 9899:1999(E)§6.2.5/ 9)
如您所见,(unsigned)0 - (unsigned)1
等于-1模UINT_MAX + 1,或换句话说,UINT_MAX。
请注意,虽然它确实说“涉及无符号操作数的计算永远不会溢出”,这可能导致您认为它仅适用于超出上限,但这被表示为句子的实际绑定部分的动机:“a无法用结果无符号整数类型表示的结果以模数减少为模数,该数字大于可由结果类型表示的最大值。该短语不限于类型上限的溢出,并且同样适用于太低而无法表示的值。
TA贡献1835条经验 获得超7个赞
使用无符号类型时,会发生模运算(也称为“环绕”行为)。要理解这种模块化算法,只需看看这些时钟:
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)
// ...
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_MAX
中c
,即使该平台采用异国情调的代表符号整数。
- 3 回答
- 0 关注
- 987 浏览
添加回答
举报