【问题标题】:signed and unsigned integer in CC中的有符号和无符号整数
【发布时间】:2015-01-24 03:12:36
【问题描述】:

我编写了这个程序作为练习来理解有符号和无符号整数如何 在 C 工作。 这段代码应该只打印-9 加上存储在变量c 中的-4+-5

#include <stdio.h>

int main (void) {
  unsigned int a=-4;
  unsigned int b=-5;

unsigned int c=a+b;
printf("result is %u\n",c);

return 0;
}

当这段代码运行时,它会给我一个意想不到的结果4294967287。 我也将cunsigned 转换为signed integer printf ("result is %u\n",(int)c); 但也不起作用。

请有人解释为什么程序没有给出确切的结果?

【问题讨论】:

  • 你期待什么结果?你知道“补码”表示吗?
  • 只需将-9 添加到变量c 中存储的c,我已经编辑了我的问题。
  • 您将其作为实验。现在您知道会发生什么,您应该阅读有关数字的存储方式以及语言如何解释它们的信息。看看你是否可以预测当你尝试一些其他时髦的计算时会发生什么 - 然后尝试它们

标签: c types casting unsigned signed


【解决方案1】:

你期望这样:

printf("result is %u\n",c);

打印-9。这不可能。 cunsigned int 类型,%u 打印一个 unsigned int 类型的值(使用正确的格式字符串作为参数做得很好)。 unsigned int 对象不能存储负值。

回到程序中的几行:

unsigned int a=-4;

4 是类型(有符号)int,具有明显的价值。将一元 - 应用于该值会产生 int-4

到目前为止,一切都很好。

现在,当您将这个负的 int 值存储在 unsigned int 对象中时会发生什么?

它是转换的

语言指定了当您将带符号的int 值转换为unsigned int 时会发生什么:该值被调整为在unsigned int 的范围内。如果unsigned int 是 32 位,则可以根据需要多次加或减 232。在这种情况下,结果是 -4 + 232,或 4294967292。 (如果你以十六进制显示这个数字会更有意义:0xfffffffc。)

(生成的代码真的不会重复加或减 232;它会做任何需要做的事情来获得相同的结果。使用二进制补码表示有符号整数很酷的一点是它不必做任何事情int 的值 -4unsigned int 的值 4294967292 完全相同位表示。规则是根据值定义的,但它们的设计是为了可以使用按位运算轻松实现。)

同样,c 的值为 -5 + 232,或 4294967291

现在您将它们加在一起。 数学结果是8589934583,但这不适合unsigned int。使用与转换类似的规则,将结果减少到unsigned int 范围内的值,产生4294967287(或者,在十六进制中,0xfffffff7)。

您还尝试了演员表:

printf ("result is %u\n",(int)c);

在这里,您将int 参数传递给printf,但您已经告诉它(通过使用%u)期待unsigned int。您还尝试转换一个太大而无法放入int 的值——当值超出范围时,无符号到有符号的转换规则不会定义此类转换的结果。所以不要那样做。

【讨论】:

    【解决方案2】:

    如果这是一个 c 和有符号与无符号的练习,你应该从思考开始 - 这是什么意思?

     unsigned int a=-4;
    

    它甚至应该编译吗?这似乎是一个矛盾。

    使用调试器检查存储在 a 位置的内存。你认为在这种情况下会一样吗?

     int a=-4;
    

    当编译器被要求将无符号 x 添加到无符号 y 时,编译器是否会做不同的事情,而不是有符号 x 和有符号 y。让编译器向你展示它在每种情况下生成的机器代码,阅读指令的作用

    探索调查验证,您有机会获得有关计算机实际工作方式的真正有趣的见解

    【讨论】:

      【解决方案3】:

      用谷歌,两秒就能找到答案..

      http://en.wikipedia.org/wiki/Signedness

      For example, 0xFFFFFFFF gives −1, but 0xFFFFFFFFU gives 4,294,967,295
      for 32-bit code
      

      因此,在这种情况下,您的4294967287 是预期的。

      但是,“从无符号转换为有符号不起作用”究竟是什么意思?

      【讨论】:

        【解决方案4】:

        这个答案对于 32 位整数是完全正确的。

        unsigned int a = -4;
        

        a 设置为位模式0xFFFFFFFC,解释为无符号位,即4294967292 (232 - 4)。同样,b 设置为 232 - 5。当你将两者相加时,你会得到 0x1FFFFFFF7 (8589934583),它比 32 位更宽,所以多余的位被丢弃,留下 4294967287,其中,碰巧是 232 - 9。因此,如果您对有符号整数进行了此计算,您将得到完全相同的位模式,但 printf 会将答案呈现为 @987654325 @。

        【讨论】:

        • 感谢您的回答。你能解释一下为什么 cast 在那个程序中不起作用吗?
        • 我的意思是当我将 printf 表达式更改为 printf ("result is %u\n",(int)c); 时,为什么这不起作用?
        • printf 解释它的参数,但是你在格式参数中告诉它。由于您使用了%u,它会将参数打印为无符号。它不(也不能)“知道”演员阵容,因为这是编译时的事情,而 C 是一种低级语言,它不像高级语言那样为运行时保留任何编译时信息。如果要打印单整数,请使用%d
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-10-02
        • 1970-01-01
        • 2015-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-20
        相关资源
        最近更新 更多