Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 有符号和无符号之间的减法,然后是除法_C++_Unsigned_Integer Overflow_Arithmetic Expressions - Fatal编程技术网

C++ 有符号和无符号之间的减法,然后是除法

C++ 有符号和无符号之间的减法,然后是除法,c++,unsigned,integer-overflow,arithmetic-expressions,C++,Unsigned,Integer Overflow,Arithmetic Expressions,以下结果让我非常困惑: 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相同 IIRC,有符号和无符号整数之间的算术运算将产生无符号结果 因此,20-80u产生的无符号结果相当于-

以下结果让我非常困惑:

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
    相同

  • IIRC,有符号和无符号整数之间的算术运算将产生无符号结果

    因此,
    20-80u
    产生的无符号结果相当于
    -60
    :如果
    无符号int
    是32位类型,则该结果为4294967236

    顺便说一句,将其分配给
    i1
    会产生一个实现定义的结果,因为该数字太大,无法容纳。获得
    -60
    是典型的,但不能保证

    这里有微妙的恶魔操作数不同,因此需要进行转换。两个操作数都转换为公共类型(在本例中为
    无符号int
    )。结果将是一个大的
    无符号int
    值(如果我的计算正确,则小于
    UINT_MAX+1
    60),在存储到
    i1
    之前,它将被转换为
    int
    。由于该值超出了
    int
    的范围,因此结果将由实现定义,可能是陷阱表示,因此在尝试使用它时可能会导致未定义的行为。但是,在您的情况下,它会同时转换为
    -60


    从第一个示例继续,我猜测
    20-80u
    的结果将比
    UINT_MAX+1
    小60。如果
    UINT_MAX
    是4294967295(一个
    UINT_MAX
    的公共值),这意味着
    20-80u
    4294967236
    。。。而
    4294967236/2
    是2147483618



    至于
    i2
    和其他,应该不会有什么意外。它们遵循传统的数学计算,没有任何转换、截断、溢出或其他实现定义的行为。

    二进制算术运算符将对其操作数执行操作,以将其转换为通用类型

    i1
    i3
    i5
    的情况下,常见类型将是无符号int,因此结果也将是无符号int。无符号数字将通过模运算进行换行,因此减去稍大的无符号值将导致接近无符号int max的数字,而该数字不能用int表示

    因此,在
    i1
    的情况下,由于无法表示值,因此我们最终会进行实现定义的转换。在
    i3
    除以
    2
    的情况下,无符号值会回到int的范围内,因此我们在转换后得到一个大的有符号int值

    <> >相关章节构成C++草稿标准如下。第5.7节
    5.7
    [expr.add]:

    加法运算符+和-从左向右分组。通常的算术转换是针对 算术或枚举类型的操作数

    第5节介绍了常用的算术转换,其中说明:

    许多需要算术或枚举类型操作数的二进制运算符会导致转换并产生 结果类型以类似的方式显示。目的是生成一个公共类型,它也是结果的类型。 此模式称为常用算术转换,其定义如下:

    [……]

    • 否则,如果具有无符号整数类型的操作数的秩大于或等于 另一个操作数类型的秩,有符号整数类型的操作数应转换为 具有无符号整数类型的操作数的类型
    对于无法表示有符号类型的值的转换,请参见第
    4.7节
    [conv.integral]:

    如果目标类型是有符号的,则如果可以在目标类型(和)中表示该值,则该值将保持不变 位域宽度);否则,该值由实现定义

    对于无符号整数,遵循模算术部分
    3.9.1
    [basic.basical]:

    无符号整数应遵循算术模2n定律,其中n是值中的位数 表示整数的特定大小。48


    顺便提一下,将该值指定给i1是未定义的行为,您确定吗?我教过,对于无符号int的所有值,从无符号int到有符号int的转换都有很好的定义。这里没有符号整数溢出。有转换。看。@rozina:嗯,我以前从来没有见过转换在这方面有不同的效果。如果我理解正确的话,将-1转换为unsigned是很好定义的,它是UINT_MAX。但是如果你将UINT_MAX转换回int,它会突然被实现定义吗?不可能是-1吗?回答得很好:)@Hurkyl:该死,我今天站着睡觉,我弄坏了未签名的溢出和从未签名到已签名的转换(后者由实现定义)。我会自毁我的评论。。。
    int i1 = 20-80u;    // -60
    
    int i3 =(20-80u)/2; // 2147483618