有符号和无符号之间的减法,然后是除法
Posted
技术标签:
【中文标题】有符号和无符号之间的减法,然后是除法【英文标题】:Subtraction between signed and unsigned followed by division 【发布时间】:2015-12-05 06:52:58 【问题描述】:下面的结果让我很困惑:
int i1 = 20-80u; // -60
int i2 = 20-80; // -60
int i3 =(20-80u)/2; // 2147483618
int i4 =(20-80)/2; // -30
int i5 =i1/2; // -30
i3
似乎被计算为 (20u-80u)/2
,而不是 (20-80u)/2
据说i3
和i5
是一样的。
【问题讨论】:
【参考方案1】:int i1 = 20-80u; // -60
这有微妙的恶魔!操作数不同,因此需要转换。两个操作数都转换为通用类型(在本例中为unsigned int
)。结果将是一个大的unsigned int
值(如果我的计算正确,则比UINT_MAX + 1
小60)将在存储到i1
之前转换为int
。由于该值超出了int
的范围,因此结果将由实现定义,可能是陷阱表示,因此在您尝试使用它时可能会导致未定义的行为。但是,在您的情况下,它巧合地转换为 -60
。
int i3 =(20-80u)/2; // 2147483618
从第一个例子继续,我猜20-80u
的结果会比UINT_MAX + 1
少60。如果 UINT_MAX
是 4294967295(UINT_MAX
的常用值),则意味着 20-80u
是 4294967236
... 而 4294967236 / 2
是 2147483618。
至于i2
等人,应该不会有什么意外吧。它们遵循传统的数学计算,没有任何转换、截断、溢出或其他实现定义的行为。
【讨论】:
所以如果我理解正确的话,将 -1 转换为无符号是明确定义的,它是 UINT_MAX。但是,如果您随后将 UINT_MAX 转换回 int 是否突然定义了实现?并且不能是-1? 很好的回答日:)【参考方案2】:二元算术运算符将对它们的操作数执行usual arithmetic conversions 以将它们带入一个通用类型。
在i1
、i3
和i5
的情况下,公共类型将为unsigned int,因此结果也是unsigned int。无符号数将通过模运算进行换行,因此减去稍大的无符号值将导致接近无符号 int 最大值的数字,该数不能用 int 表示。
所以在i1
的情况下,我们最终得到了实现定义的转换,因为无法表示值。在i3
除以2
的情况下,无符号值又回到了 int 的范围内,因此我们在转换后得到一个大的有符号 int 值。
C++ 标准草案的相关部分如下。部分5.7
[expr.add]:
加法运算符 + 和 - 从左到右分组。通常的算术转换是为 算术或枚举类型的操作数。
5
部分介绍了常用的算术转换,它说:
许多期望算术或枚举类型操作数的二元运算符会导致转换和产生 结果类型以类似的方式。目的是产生一个通用类型,这也是结果的类型。 这种模式称为通常的算术转换,定义如下:
[...]
否则,如果具有无符号整数类型的操作数的秩大于或等于 其他操作数类型的等级,带符号整数类型的操作数应转换为 无符号整数类型的操作数的类型。
对于从无法表示为有符号类型的值的转换,4.7
部分 [conv.integral]:
如果目标类型是有符号的,如果它可以在目标类型中表示,则值不变(并且 位域宽度);否则,该值是实现定义的。
对于无符号整数遵循模运算部分3.9.1
[basic.fundamental]:
无符号整数应遵循算术模 2n 的定律,其中 n 是值中的位数 表示特定大小的整数.48
【讨论】:
@Hurkyl:该死,我今天站着睡觉,我破坏了无符号溢出和从无符号到有符号的转换(后者是实现定义的)。我会自毁我的评论...【参考方案3】:IIRC,有符号和无符号整数之间的算术运算将产生无符号结果。
因此,20 - 80u
产生等同于 -60
的无符号结果:如果 unsigned int
是 32 位类型,则结果为 4294967236。
顺便说一句,将其分配给 i1
会产生 实现定义 结果,因为该数字太大而无法容纳。获取-60
是典型的,但不能保证。
【讨论】:
顺便说一下,将该值分配给 i1 是未定义的行为您确定吗?我教过从 unsigned int 到有符号 int 的转换对于 unsigned int 的所有值都有很好的定义。 这里没有有符号整数溢出。有转换。见conv.integral。 @rozina:嗯,我以前从未见过转换在这方面的工作方式不同。固定以上是关于有符号和无符号之间的减法,然后是除法的主要内容,如果未能解决你的问题,请参考以下文章