Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.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++ 为什么((无符号整数)x)*y==((无符号整数)(x*y)总是真的?_C++_Implicit Conversion - Fatal编程技术网

C++ 为什么((无符号整数)x)*y==((无符号整数)(x*y)总是真的?

C++ 为什么((无符号整数)x)*y==((无符号整数)(x*y)总是真的?,c++,implicit-conversion,C++,Implicit Conversion,我刚刚写了这些代码: int x = -1;//x must be negative unsigned int y = 1;//y must be positive bool b; for(; ; x--, y++){ b = ((unsigned int)x) * y == ((unsigned int)(x * y)); } 然后我发现b总是正确的。在我看来,((unsigned int)x)*y会溢出,但((unsigned int)(x*y))不会。我真的很难相信这是真的。这只

我刚刚写了这些代码:

int x = -1;//x must be negative
unsigned int y = 1;//y must be positive
bool b;
for(; ; x--, y++){
    b = ((unsigned int)x) * y == ((unsigned int)(x * y));
}
然后我发现
b
总是正确的。在我看来,((unsigned int)x)*y会溢出,但((unsigned int)(x*y))不会。我真的很难相信这是真的。这只是巧合还是这一现象背后有什么规律

这仅仅是巧合还是这种现象背后有什么规律

不,这不是巧合,这可以用通常的算术转换执行的隐式转换来解释

乘法运算符对其操作数执行运算,使其成为公共类型,对于此子表达式:

(unsigned int)(x * y)
将导致
x
转换为无符号整数。这将导致:

(unsigned int)(x * y)
相当于:

((unsigned int)x) * y
很多时候,使用正确的警告标志有助于解决难题,使用gcc的
-Wall
,它会给出以下警告:

warning: self-comparison always evaluates to true [-Wtautological-compare]
   b = ((unsigned int)x) * y == ((unsigned int)(x * y));
                             ^
使用带有叮当声的
-Wconversion
标志会发出以下警告():

<参考文献> C++标准部分<代码> 5.6 >代码> [EXPR.MUL]:< < /P> 通常的算术转换是在操作数上执行的 并确定结果的类型

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

否则,应在两个操作数上执行积分提升(4.5)。61然后执行以下操作 规则应适用于升级的操作数:

[……]

  • 否则,如果具有无符号整数类型的操作数的秩大于或等于 另一个操作数类型的秩,有符号整数类型的操作数应转换为 具有无符号整数类型的操作数的类型
< P> >在C++第4.13版<代码> > [Vang.Req]:

任何无符号整数类型的秩应等于相应有符号整数类型的秩


x*y
中,
x
已通过通常的算术转换转换为
无符号
。§5/10:

也就是说,您的第一个表达式,
(无符号)(x*y)
,相当于
(无符号)(无符号)x*y)
,而
(无符号)x*y
——您的第二个表达式


注意,
unsigned int
的秩等于(
signed
int
的秩,按§4.13/1.4:

任何无符号整数类型的秩应等于 对应的有符号整数类型


这里有两个要点:

  • 常用的算术转换

  • 无符号整数算术不能溢出

  • 引用标准:

    §5表达方式[expr]

    9许多期望操作数为的二进制运算符 算术或枚举类型导致转换并产生结果 类型。其目的是生成一个通用类型 也是结果的类型。此模式称为通常模式 算术转换,定义如下:

    [……]

    -否则,如果具有无符号整数类型的操作数的秩大于或等于 另一个操作数类型的秩,带符号整数类型的操作数应转换为 无符号整数类型的操作数类型

    因此(第1点),当两个操作数的秩相同时,有符号的操作数将转换为无符号类型。因此
    ((无符号整数)x)*y
    ((无符号整数)(x*y))的求值总是相同的

    现在让我们看看它们是否总是有效的

    §3.9.1基本类型[基本.基本]

    4个无符号整数,声明为无符号,应遵守算术模2n定律,其中n是数字 整数的特定大小的值表示中的位。46

    46)这意味着无符号算术不会溢出,因为结果不能表示结果 无符号整数类型是按大于可由 结果无符号整数类型


    因此(第2点),
    ((无符号整数)x)*y将不会溢出(也不会
    y
    ,尽管
    x
    将随着for循环的进行而发生未定义的行为)。

    既不会
    ((无符号整数)x)*y
    也不会
    (无符号整数)(x*y)
    溢出,因为无符号算术不能溢出。看看我的答案。这个表达式((无符号int)x)*y==((无符号int)(x*(int)y))是否总是真的?这只是巧合吗?它总是真的,因为我的答案的第一点:你所写的正是通常算术转换的工作原理。在等式的左侧,您显式地将有符号操作数强制转换为其无符号类型,而在右侧,编译器隐式地执行相同的操作。假设x=-2,y=2,那么左侧表达式等于4294967294*2,右侧表达式等于(无符号整数)(-4),为什么4294967294*2等于(无符号整数)(-4)?这对于x<0和y>0都是正确的。对于
    x=-2
    y=2
    ,编译器将正确的表达式计算为
    (unsigned int)(4294967294*2)
    (如果
    int
    由4个字节表示);事实上,通常的算术转换在计算无符号整数之前将其转换为
    x
    。什么是
    rank great
    ,什么是rank?@Yola I添加了相关的段落。基本上,所有整数类型都是排序的。它是这样的(自下而上):{
    bool
    },{
    char
    signed char
    unsigned char
    },{
    short
    unsigned short
    },{
    int
    unsigned int
    }…
    warning: implicit conversion changes signedness: 'int' to 'unsigned int' [-Wsign-conversion]
    b = ((unsigned int)x) * y == ((unsigned int)(x * y));
                                                 ^ ~