我有两个函数add和main如下。
int add(unsigned int a, unsigned int b)
{
return a+b;
}
int main()
{
unsigned int a,b;
cout << "Enter a value for a: ";
cin >> a;
cout << "Enter a value for b: ";
cin >> b;
cout << "a: " << a << " b: "<<b <<endl;
cout << "Result is: " << add(a,b) <<endl;
return 0;
}
当我运行此程序时,我得到以下结果:
Enter a value for a: -1
Enter a value for b: -2
a: 4294967295 b: 4294967294
Result is: -3
为什么结果是-3?
答案 0 :(得分:6)
因为add
返回int
(无unsigned int
),它不能代表4294967295 + 4294967294 = 4294967293
(无符号整数算术在mod 2^n
中定义为n = 32
这种情况)因为结果太大了。
因此,您已经签署了整数溢出(或者更确切地说,是一个无法表示为int
的源整数的隐式转换),它具有实现定义的结果,即任何输出(可表示为{ {1}})将是“正确的”。
准确获取int
的原因是结果为-3
,并且会在您的系统上转换为2^32 - 3
。但是,请注意,任何结果都是合法的。
答案 1 :(得分:1)
int add(unsigned int a, unsigned int b)
{
return a+b;
}
表达式a+b
添加两个类型为unsigned int
的操作数,产生unsigned int
个结果。严格来说,无符号加法不会“溢出”;模数MAX + 1,而不是结果减少,其中MAX是无符号类型的最大值。在这种情况下,假设32位unsigned int
,添加4294967295 + 4294967294
的结果已明确定义:它是4294967293
或2 32 -3。
由于add
被定义为返回int
结果,因此unsigned
值会从unsigned int
隐式转换为int
。与算术溢出不同,无法在目标类型中表示的无符号到符号转换会产生实现定义的结果。在典型的实现中,这样的转换(源和目标具有相同的大小)将重新解释表示,产生-3
。取决于实施,其他结果也是可能的,但不是特别可能。
至于为什么a
和b
首先被设置为这些值,显然当cin >> a
是无符号值并且输入为a
时,add
的行为如何负。我不确定该行为是由语言,实现定义还是未定义来定义的。在任何情况下,一旦有了这些值,<?php
$a = array(1 => 'a', 2 => 'b', 3 => 'c');
$b = serialize($a);
var_dump($b); ////Returns this string(42) "a:3:{i:1;s:1:"a";i:2;s:1:"b";i:3;s:1:"c";}"
$c = unserialize($b);
print_r($c); //Return the same thing as $a
返回的结果就会如上所述。
答案 2 :(得分:0)
如果您打算返回unsigned int,则需要将unsigned添加到函数声明中。如果您将返回类型更改为unsigned int 并使用值-1和amp; -2那么这将是你的输出:
a: 4294967295 b: 4294967294
Result: 4294967293
unsigned int范围为[0,4294967295],前提是unsigned int在本地计算机上的大小为4bytes。当您为unsigned int输入-1时,您有缓冲区溢出,这里发生的是编译器将-1设置为unsigned int中可能的最大有效数字。当你将-2传递给你的函数时,会发生同样的事情,但是你将索引回到第二大值。使用unsigned int时,没有&#34;符号&#34;存储的负数。如果你通过(a)得到无符号的最大可能值并加上1它将给你一个值0.这些值被传递给函数,并且该函数在这个函数中创建了2个局部作用域的堆栈变量。 所以现在你有一份&amp; b在堆栈上,a的值为unsigned int max size,b的值为unsigned int max size - 1.现在,您要对这两个超出unsigned int的最大值大小的值执行加法,并且发生换行在相反的方向。因此,如果索引值从..... 95开始并且你加1,这给你最后一位数字0,所以如果你取第二个值,即最大值 - 1:..... 94从中减去一个因为我们现在已达到0,所以我们正朝着积极的方向发展。这将给你一个...... 93的结果,如果你的返回类型是unsigned int,函数将返回。
如果您的返回类型为int,则适用同样的概念,但是这里会发生什么 是这样的:添加两个无符号值与给出的结果相同 ..... 93然后编译器将隐式地将其转换为int。那么这里签名int的范围值是-2147483648到2147483647 - 一位用于存储(有符号值),但它还取决于是否正在使用两个恭维等。
这里的编译器非常聪明,知道signed int有一系列这些值,但仍然会发生包装。当我们将4294967293存储到一个有罪的int中时会发生什么?那么int中的最大值是2147483647所以如果我们减去这两个(4294967293 - 2147483647),我们就会得到2147483646。此时此值是否适合有符号的int max值?然而,由于隐式转换是从无符号到有符号值完成的,我们有2位要考虑,签名本身和包装值意味着max_value + 1 = 0要考虑,除了这不会发生如果在max_value中添加1,则使用带符号的值可以得到最大的-max_value。
对于无符号值:
- ...95 = -1
- ...94 = -2
- ...93 = -3
对于带符号的值,否定值将保留在其自己的位中,或者如果使用了两个补码等,则对编译器中的signed int的定义挂起。这里编译器将此无符号值识别为负值,即使负值未存储在无符号值中也不会保留符号。因此,当它显式地从无符号转换为有符号的一位用于存储有符号的值时,则完成计算并从缓冲区溢出进行包装。因此,当我们减去实际的无符号值(表示-3:4294967293)和带有符号的int 2147483647的max +值时,我们现在使用带符号的int得到值2147483646如果你将最大值加1,它就不会像无符号那样给你0它会给你一个最大的符号值,对于4byte int是-2147483648,因为它确实适合max +值,并且编译器知道如果我们将余数加到-max_value,这应该是一个负值对于一个有符号的int:2147483646 +( - 2147483648)这会给我们-2,但是因为int包装是不同的,所以我们必须从-2减去1 - 1 = -3。
答案 3 :(得分:-1)
当它从unsigned int转换为int时,该数字超过了有符号整数可以容纳的数字。这会导致它作为负值溢出。
如果将返回值更改为无符号整数,则应解决问题。