有符号和无符号之间的减法,然后除法
Subtraction between signed and unsigned followed by division
下面的结果让我很困惑:
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
相同。
在有符号整型和无符号整型之间进行算术运算,将产生一个无符号整型。
因此,20 - 80u
产生的unsigned结果相当于-60
:如果unsigned int
是32位类型,则结果为4294967236。
i1
会产生一个实现定义的结果,因为这个数字太大而无法匹配。获得-60
是典型的,但不能保证。
int i1 = 20-80u; // -60
这有微妙的恶魔!操作数是不同的,所以必须进行转换。两个操作数都被转换为一个通用类型(在本例中是unsigned int
)。结果,这将是一个大的unsigned int
值(60小于UINT_MAX + 1
如果我的计算是正确的)将被转换为int
之前,它被存储在i1
。由于该值超出了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
和其他的,不应该有什么意外。它们遵循传统的数学计算,没有转换、截断、溢出或其他实现定义的行为。
二进制算术运算符将对其操作数执行通常的算术转换,使其成为公共类型。
对于i1
、i3
和i5
,通用类型将是unsigned int,因此结果也将是unsigned int。无符号数将通过模运算进行换行,因此减去稍大的无符号值将得到一个接近Unsigned int max的数字,该数字无法用int表示。
所以在i1
的情况下,我们最终使用实现定义的转换,因为值不能表示。在i3
除以2
的情况下,unsigned值又回到了int的范围内,因此我们在转换后得到了一个大的signed int值。
c++标准草案的相关章节如下:Section 5.7
[expr.add]:
加性运算符+和-从左到右分组。执行通常的算术转换算术或枚举类型的操作数。
通常的算术转换在5
节中介绍,它说:
许多要求操作数为算术或枚举类型的二元操作符会导致转换并产生结果结果以类似的方式类型。目的是产生一个公共类型,这也是结果的类型。这种模式称为常规算术转换,定义如下:
[…]
- 否则,如果无符号整数类型的操作数的排名大于等于另一个操作数的类型为秩,具有符号整型的操作数应转换为无符号整型操作数的类型
,对于不能用符号类型表示的值的转换,参见4.7
[conv.integral]:
如果目标类型是带符号的,如果该值可以用目标类型(和)表示,则该值不变位域宽度);否则,该值为实现定义。
,对于无符号整数服从模运算章节3.9.1
[basic.fundamental]:
无符号整数应遵循算术模数2n的法则,其中n为该值的位数表示特定大小的整数。48
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 这是我尝试让用户将值输入到数组中.然后将其隐藏为大量的星号
- boost::asio如何生成多个协同程序,然后加入它们
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- 在std::thread中,joinable()然后join()线程安全吗
- 在除法中不需要四舍五入
- C++:如何读取分离变量,然后读取向量
- 为什么我的递归函数按降序打印,然后按升序打印?
- 等待整个 omp 块完成,然后再调用第二个函数
- CMake:如何将库 A 链接到库 B,然后将可执行文件链接到库 A
- 在TFHE(完全快速同态加密)上执行除法
- 使用 int 表示浮点除法 C++
- 如何存储用户输入的所有数据,然后在他们想要查看所有数据时显示它们
- '{'标记之前的预期类名,然后在预声明时无效使用不完整的类型'class class_name'
- 如何使变量从 x 到 y,然后从 y 返回到 x 并始终重复该过程
- 我有一个数组,我想输入一个范围,然后找到范围内所有偶数的总和?
- 如何正确地推回然后遍历堆中对象的向量?
- 有符号和无符号之间的减法,然后除法
- 做一个可能溢出的乘法然后用除法验证