带有unsigned int参数的C++函数在使用negative调用它时会得到奇怪的结果



我是C++的新手,我对以下代码的C++行为感到困惑:

#include <iostream>
void hello(unsigned int x, unsigned int y){
std::cout<<x<<std::endl;
std::cout<<y<<std::endl;
std::cout<<x+y<<std::endl;
}
int main(){
int a = -1;
int b = 3;
hello(a,b);
return 1;
}

输出中的x是一个非常大的整数:4294967295,我知道将负整数转换为无符号会有这样的行为。但是为什么输出中的x+y是2呢?

与其他答案相反,这里没有未定义的行为,也没有溢出。无符号整数使用模2n算术。

该标准第4.7节第2段规定:"如果目标类型是无符号的,则得到的值是与源整数全等的最小无符号整数(模2n,其中n是用于表示无符号类型的位数)。"这表明-1等于最大可能的无符号整数。

第3.9.1节第4段规定:"声明为无符号的无符号整数应遵守算术模2n的定律,其中n是该特定大小整数的值表示中的位数。"为了明确这意味着什么,该子句的脚注中写道:"这意味着无符号算术不会溢出,因为无法由结果的无符号整数类型表示的结果被模减为比结果的无签名整数类型所能表示的最大值大一的数字。">


换句话说,将-1转换为4294967295不仅仅是定义的行为,它是必需的行为(假设为32位整数)。类似地,在该值上加3并因此产生2也是必需的行为。在这种情况下,n的值是不相关的。hello()打印的第三个值必须是2,否则实现不符合标准。

因为无符号int会溢出。换句话说,a=-1(有符号),它比无符号int的最大值4294967295低1个值。然后添加3,int将溢出并从0开始,因此-1+3=2

将负数作为参数传递给无符号int会产生未定义的行为。默认的int是有符号的。其范围为–2147483648到2147483647。无符号int的范围从0到4294967295。

这与C++无关,而是与计算机如何表示有符号和无符号数字有关。

这是一个很好的消息来源。基本上,有符号数字(通常)是用2的补码表示的,其中最高有效位的值为-2^n。实际上,他的意思是,正数在二的补码中的表示与在正则无符号二进制中的表示相同。

-1表示为全1,当被解释为无符号整数时,它将是可以表示的最大整数(4294967295,当处理32位时)。

使用两个补码来表示有符号数的一个好处是,你可以用与无符号数完全相同的方式执行加法和减法,只要数字不超过可以表示的界限,它就会正确计算。这对于其他形式(如符号星等)来说并不容易。

这意味着,因为-1+3=2的结果,并且因为2是正的,所以它将被解释为与无符号的结果相同。因此,它打印2。

最新更新