为什么unsigned int在c ++中给出负值?

时间:2015-05-04 17:46:36

标签: c++ unsigned-integer

我有两个函数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?

4 个答案:

答案 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。取决于实施,其他结果也是可能的,但不是特别可能。

至于为什么ab首先被设置为这些值,显然当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时,该数字超过了有符号整数可以容纳的数字。这会导致它作为负值溢出。

如果将返回值更改为无符号整数,则应解决问题。