我遇到过某人的代码,他似乎认为当结果为负数时从另一个相同类型的整数中减去无符号整数会出现问题。因此,即使这样的代码恰好适用于大多数架构,它也是不正确的。
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 == (unsigned)(0 + -1) == (0xFFFF but还有 0xFFFE 或 0x8001)
哪个或哪种解释是正确的?它有定义吗?
I have come across code from someone who appears to believe there is a problem subtracting an unsigned integer from another integer of the same type when the result would be negative. So that code like this would be incorrect even if it happens to work on most architectures.
unsigned int To, Tf;
To = getcounter();
while (1) {
Tf = getcounter();
if ((Tf-To) >= TIME_LIMIT) {
break;
}
}
This is the only vaguely relevant quote from the C standard I could find.
A computation involving unsigned operands can never overflow, because a
result that cannot be represented by the resulting unsigned integer
type is reduced modulo the number that is one greater than the largest
value that can be represented by the resulting type.
I suppose one could take that quote to mean that when the right operand is larger the operation is adjusted to be meaningful in the context of modulo truncated numbers.
i.e.
0x0000 - 0x0001 == 0x 1 0000 - 0x0001 == 0xFFFF
as opposed to using the implementation dependent signed semantics:
0x0000 - 0x0001 == (unsigned)(0 + -1) == (0xFFFF but also 0xFFFE or 0x8001)
Which or what interpretation is right? Is it defined at all?
发布评论
评论(6)
当您使用无符号类型时,模算术 (也称为“环绕”行为)正在发生。要理解这个模块化算术,只需看看这些时钟:
< strong>9 + 4 = 1 (13 mod 12),所以到另一个方向是:1 - 4 = 9 (-3模组12)。使用无符号类型时应用相同的原则。如果结果类型为
无符号
,则进行模算术。现在看看以下将结果存储为
unsigned int
的操作:当您想确保结果是
signed
时,请将其存储到signed
code> 变量或将其转换为signed
。当您想要获得数字之间的差异并确保不会应用模运算时,您应该考虑使用stdlib.h
中定义的 >abs() 函数:要非常小心,尤其是在编写条件时,因为:
but
When you work with unsigned types, modular arithmetic (also known as "wrap around" behavior) is taking place. To understand this modular arithmetic, just have a look at these clocks:
9 + 4 = 1 (13 mod 12), so to the other direction it is: 1 - 4 = 9 (-3 mod 12). The same principle is applied while working with unsigned types. If the result type is
unsigned
, then modular arithmetic takes place.Now look at the following operations storing the result as an
unsigned int
:When you want to make sure that the result is
signed
, then stored it intosigned
variable or cast it tosigned
. When you want to get the difference between numbers and make sure that the modular arithmetic will not be applied, then you should consider usingabs()
function defined instdlib.h
:Be very careful, especially while writing conditions, because:
but
在无符号类型中生成负数的减法结果是明确定义的:
如您所见,
(unsigned)0 - (unsigned)1
等于 -1 模 UINT_MAX+1,换句话说,UINT_MAX。请注意,虽然它确实说“涉及无符号操作数的计算永远不会溢出”,这可能会让您相信它仅适用于超过上限,但这被视为实际绑定的动机句子的一部分:“无法用结果无符号整数类型表示的结果是
减少对比最大值大 1 的数取模
由结果类型表示。”该短语不限于类型上限的溢出,并且同样适用于太低而无法表示的值。
The result of a subtraction generating a negative number in an unsigned type is well-defined:
As you can see,
(unsigned)0 - (unsigned)1
equals -1 modulo UINT_MAX+1, or in other words, UINT_MAX.Note that although it does say "A computation involving unsigned operands can never overflow", which might lead you to believe that it applies only for exceeding the upper limit, this is presented as a motivation for the actual binding part of the sentence: "a result that cannot be represented by the resulting unsigned integer type is
reduced modulo the number that is one greater than the largest value that can be
represented by the resulting type." This phrase is not restricted to overflow of the upper bound of the type, and applies equally to values too low to be represented.
嗯,第一个解释是正确的。但是,您在这种情况下对“签名语义”的推理是错误的。
再说一次,你的第一个解释是正确的。无符号算术遵循模算术规则,这意味着对于 32 位无符号类型,
0x0000 - 0x0001
计算结果为0xFFFF
。然而,还需要第二种解释(基于“签名语义”的解释)才能产生相同的结果。即即使你在有符号类型的域中计算
0 - 1
并获得-1
作为中间结果,这个-1
仍然是必需的稍后转换为无符号类型时生成0xFFFF
。即使某些平台使用有符号整数的奇异表示(1 的补码、有符号大小),该平台在将有符号整数值转换为无符号整数值时仍然需要应用模算术规则。例如,
即使平台使用有符号整数的奇异表示,此评估仍然可以保证在
c
中生成UINT_MAX
。Well, the first interpretation is correct. However, your reasoning about the "signed semantics" in this context is wrong.
Again, your first interpretation is correct. Unsigned arithmetic follow the rules of modulo arithmetic, meaning that
0x0000 - 0x0001
evaluates to0xFFFF
for 32-bit unsigned types.However, the second interpretation (the one based on "signed semantics") is also required to produce the same result. I.e. even if you evaluate
0 - 1
in the domain of signed type and obtain-1
as the intermediate result, this-1
is still required to produce0xFFFF
when later it gets converted to unsigned type. Even if some platform uses an exotic representation for signed integers (1's complement, signed magnitude), this platform is still required to apply rules of modulo arithmetic when converting signed integer values to unsigned ones.For example, this evaluation
is still guaranteed to produce
UINT_MAX
inc
, even if the platform is using an exotic representation for signed integers.对于
unsigned int
或更大类型的无符号数,在没有类型转换的情况下,ab
被定义为生成无符号数,当将其添加到b
code>,将产生a
。将负数转换为无符号数被定义为产生的数字,当与符号反转的原始数相加时,将产生零(因此将 -5 转换为无符号数将产生一个值,当与 5 相加时,将产生零) 。请注意,小于
unsigned int
的无符号数在减法之前可能会提升为int
类型,ab
的行为将取决于的大小代码>int
。With unsigned numbers of type
unsigned int
or larger, in the absence of type conversions,a-b
is defined as yielding the unsigned number which, when added tob
, will yielda
. Conversion of a negative number to unsigned is defined as yielding the number which, when added to the sign-reversed original number, will yield zero (so converting -5 to unsigned will yield a value which, when added to 5, will yield zero).Note that unsigned numbers smaller than
unsigned int
may get promoted to typeint
before the subtraction, the behavior ofa-b
will depend upon the size ofint
.好吧,无符号整数减法已经定义了行为,但这也是一件棘手的事情。当您减去两个无符号整数时,如果未显式指定结果(左值)类型,则结果将提升为更高类型 int。在后一种情况下,例如 int8_t result = a - b; (其中 a 和 b 具有 int8_t 类型)您可以获得非常奇怪的行为。我的意思是你可能会失去传递性属性(即如果a>b并且b>c它a>c) 成立。
传递性的丧失可能会破坏树型数据结构作品。必须注意不要提供用于排序、搜索、树构建的比较函数,使用无符号整数减法来推断哪个键更高或更低。
请参阅下面的示例。
Well, an unsigned integer subtraction has defined behavior, also it is a tricky thing. When you subtract two unsigned integers, result is promoted to higher type int if result (lvalue) type is not specified explicitly. In the latter case, for example, int8_t result = a - b; (where a and b have int8_t type) you can obtain very weird behavior. I mean you may loss transitivity property (i.e. if a > b and b > c it is true that a > c).
The loss of transitivity can destroy a tree-type data structure work. Care must be taken not to provide comparison function for sorting, searching, tree building that uses unsigned integer subtraction to deduce which key is higher or lower.
See example below.
std::abs 不“适合”无符号整数。但需要演员阵容。
std::abs is not "suitable" for unsigned integers. A cast is needed though.