C语言之unsigned、signed问题

我们都知道计算机的语言中只有”0”、”1”码。但是计算机语言中也有负数。我们再C语言中,unsigned是无符号数,而signed是有符号数,那么计算机有是怎样标记有符号数的正负呢。
计算机虽然只能看的”0”、”1”,但是它也懂得做个标记。计算机是通过把基本数据类型的最高位腾出来,用来存符号,同时约定如下:最高位如果是 1,表明这个数是负数,其值为除最高位以外的剩余位的值添上这个“-”号;如果最高位是 0,表明这个数是正数,其值为除最高位以外的剩余位的值。所以unsigned int取值范围为0 ~ 2^31-1,而signed int 的范围为-2^31 ~ 2^31-1(减去的1是因为还有0)。signed char 类型数其值表示的范围为 -2^7 ~ 2^7-1。

对于有符号数,我们要关心的一个重要问题是是否会溢出。因为数据的溢出有可能导致我们的程序朝着我们的相反方向发展。下面我们来看一个例子:

#include <stdio.h>
#include <unistd.h>

int main()
{
    char num = -128;
    num -= 1;

    printf("%d\n", num);      

    return 0;
}

上述结果会是多少呢?-129?然而计算机并不这样认为。它的运行结果是127。下面是运行结果:
[root@localhost Desktop]# ./test
127

这是因为-128 - 1,计算机会认为是(-128) + (-1),而负数在内存中它们都是用补码的形式存储的。同样也是以补码形式计算。-128的补码为 1000 0000,而 -1 的补码为: 1111 1111。两者相加会使符号为溢出:

数值             补码

-128 :        1000 0000
-1   :        1111 1111

-128 - 1 --> (-128) + (-1)      

              |
              |1000 0000
              |1111 1111
         _____|______________
             1|0111 1111            (结果溢出)            0111 1111  --->  127
              |

如果你在编程时,这些都是小细节,但是许多人可能在平时都会忽略。比如下面的代码:

int main()
{
    char a[1000];
    int i;
    for(i = 0; i < 1000; i++){
        a[i] = -1 - i;
    }

    printf("%d\n", strlen(a));

    return 0;
}

上述代码打印值又会是多少呢。当代码逻辑一多时,我们很容易忽略溢出问题。我刚开始看这个代码时第一反映也是1000。但是它的运行结果时255。下面使程序的运行结果:
[root@localhost Desktop]# gcc -o test UnsignedSignedTest.c
[root@localhost Desktop]# ./test
255

这是因为刚开始i = 0时, a[0] = -1; i = 1时,a[1] = -2; i = 2时,a[2] = -3; …….. , 当i = 127时,a[127] = -128; 当 i = 128时,a[128] = 127(上一个代码中推导过); ……. ; 当i = 254时, a[255] = 0; 而strlen计算大小时是在寻找 0 值。当遇到0结束。所以答案时255.

那么
int i = -20;
unsigned j = 10;
i+j 的值为多少?为什么?

我们一起计算下:

数值            原码                      补码
-20    1000 0000 0001 0100       1111 1111 1110 1100
10     0000 0000 0000 1010       0000 0000 0000 1010(整数的补码是他本身)

  |
  |1111 1111 1110 1100
  |0000 0000 0000 1010
__|_____________________                补码                     原码          数值
  |1111 1111 1111 0110     -->  1111 1111 1111 0110  --> 1000 0000 0000 1010  -->  -10
           |

代码验证:
这里写图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值