有符号/无符号的int转换会发生什么?

时间:2014-04-14 21:15:31

标签: c++

只需仔细检查。在一些教程中我找到了这样的代码:

#include <iostream>
using namespace std;

/* This program shows the difference between
 * signed and unsigned integers.
*/
int main()
{
   short int i;           // a signed short integer
   short unsigned int j;  // an unsigned short integer

   j = 50000;

   i = j;
   cout << i << " " << j;

   return 0;
}

输出:-15536​​ 50000

然后它解释了输出:&#34;上面的结果是因为表示50,000作为短无符号整数的位模式被短路解释为-15,536。&#34; < / p>

我认为这是一个错误的解释 - 或者这是一个英文问题? 我认为输出负值的原因是50000不适合2字节符号int,我错了吗?

6 个答案:

答案 0 :(得分:3)

您的答案和书籍答案是正确的

50000 = 0xc350

包含0xc350的带符号16位短整数被解释为-15,536

所以它们是正确的(位模式的解释)

如果我是32位int,那么将0xc350放入其中将被解释为50,000

所以你是对的(我太小了)

答案 1 :(得分:3)

对于特定平台,解释中的推理可能是准确的,但在我看来,它与最终打印的内容无关。说起来会更准确

  

“上述结果是因为从unsigned short int值50000到signed short int的实现定义转换返回的位模式导致值为-15,536。”

并不令人震惊,将所述值发送到std::cout将为所述值的signed short int结果生成正确的输出。更改(转换)的很重要,在这种情况下,它是实现定义的。他们的措辞很弱,并且相同的语句可以通过将任何值分配给任何整数值来应用,所以实际上他们的解释最终是< EM>无意义。


不想浪费之前的答案(在我更好地理解问题之前),享受一些轻松的阅读。要知道肯定为什么会发生这种情况,您必须参考您的实施文档以了解这种性质的转换。不是你可能想听到的答案,但背后有理由。

这是因为值促销通过整数转换排名而发生的。实际上,您收到的价值取决于实施,标准中涵盖了具体原因。

我会遗漏最基本的东西,然后了解它的内容:

C ++11§4.7整体促销[conv.integral]

  
      
  1. 整数类型的prvalue可以转换为另一个整数类型的prvalue。可以将未范围的枚举类型的prvalue转换为整数类型的prvalue。

  2.   
  3. 如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模2n,其中n是用于表示无符号类型的位数)。 [注意:在二进制补码表示中,此转换是概念性的,并且位模式没有变化(如果没有截断)。 - 尾注]

  4.   
  5. 如果目标类型已签名,则该值如果可以在目标类型(和位字段宽度)中表示,则不会更改;否则,该值是实现定义的。

  6.   
  7. 如果目的地类型是bool,请参阅4.12。如果源类型为bool,则将值false转换为零,将值true转换为一个。

  8.   
  9. 整数转化允许的转化不包含在整数转化中。

  10.   

您的平台上的signed short int无法表示值50000。因此,结果是实现定义的。从它的外观来看,你的实现只是将字节从一个存储到另一个,结果是符号位(在标准中也包含但为了简洁而省略)被点亮并且报告的数字是负数。但请记住,这是实现定义的,您不能在所有平台上依赖此结果

答案 2 :(得分:1)

首先,需要使用纯二进制系统来表示整数类型,到目前为止,教程是正确的。

其次,short必须至少为16位。如果它更多,那么你将看不到你所做的效果或任何效果。从您的描述中不清楚该教程是否盲目地假设short必然是16位(错误),或者它是否只是使用某些具体示例,并且理解它依赖于编译器等。

第三,如果无法表示值,则转换为签名类型... 是正式的实现定义行为。这意味着您无法保证价值的变化。相反,你可以原则上可以获得任何效果,例如崩溃。

[缺少其他行为的例子,因为我无法将g ++ 4.8.2哄骗到示例代码的陷阱中,即使使用-ftrapv]

...产生的值相同,如果可以表示,或者由实现定义。

也就是说,C ++保证无符号算术以模2 n 的形式执行,其中 n 是数字值表示位,例如你的例子中有16个。使用非常常见的二进制补码形式表示有符号整数,负整数值 - x 表示为 - x + 2的位模式 名词 。因此,如果从后一个值(将bitpattern的解释为无符号)开始为50 000,具有16个值位和2的补码形式,则得到有符号值50 000 - 2 16 = 50 000 - 65 536 = -15 536

答案 3 :(得分:0)

50,000以二进制表示为 - 1100 0011 0101 0000。

在有符号位中,最左边的位是符号。在有符号整数中,'0'表示负数(因此为-15536​​),其中在无符号整数中,这将没有区别。至于数字本身发生变化的原因,我不知道。

答案 4 :(得分:0)

你是对的,这本书也是正确的。 unsigned short的值可以是0到65535. signed short的值可以是-32768到32767.因此,0到32767之间的任何值都适用于signed和{{1} }。

但是,50000这样的数字对于unsigned来说太大了,所以当您将{500}分配给signed short时,会导致数字溢出。

答案 5 :(得分:0)

unsigned short是一个不使用符号位的16位值 - 假设所有值都是正值。

二进制存储的十进制值50,000是

1100 0011 0101 0000
^

最左边的位(最高有效位 - MSB)为1,代表2^15,即32,768

整个位模式是32,768 + 16,384 + 512 + 256 + 64 + 16 = 50,000

当您将其转换为签名短片时,位模式未更改,但MSB不再代表32,768 - 它现在代表符号< / em>的数字,其余的位是值的2的补码。在有符号值中,该顶部位是符号,1是负数

这不会发生在30,000,因为那是

0111 0101 0011 0000
^

当转换为 signed 时,最左边的0表示符号,0表示,因此其余位仍然被解释为它们不是二元补码,因此它们仍然代表相同的值30,000