C语言深度剖析学习笔记-补码

补码

按我自己的理解,补码其实很简单,就是一个用无符号数(状态)表示有符号数的过程,因为计算机底层0101本身就没符号的概念,所以将有符号数建立在无符号数基础上也很自然:

                         128  |  * 
                     129      |      127
                 130          |          126
              131             |              125
                 ...          |          ...
                     254      |      2
                         255  |  1
                          *   |  0

注: ‘*’代表没有对应值, 同一行的两个数相加恒等于256(0除外);

如上图所示,我们以一个字节为例,也就是char类型,竖线右边的值对应二进制最高位为0,左边对应二进制最高位为1,更宽的数据以此类推:

  • 当为unsigned char时:数据范围从0逆时针到255,一共256种状态;
  • 当为signed char / char时,数据范围从(-128) - 127,竖线左边为负值对应的补码(其原码就是对应的竖线右边的那个值取负,如254对应的原码就是-2), 右边为正值补码(正值的补码=原码);
  • 对于8 bits,0-255就是所有的256中状态,计算机只存储0-255对应的二进制,如果要用有符号,我把左边解析成负数,右边解析成正数就行了;
  • 有了上面的图解析过程就很简单了;
    • 从内存取出二进制值(补码) val;
    • 当val的最高位为0时,就把val的值作为解析结果;
    • 当val的最高位为1时,就把val-256的值作为解析结果;
  • 问题是第三步, 总不能为了解析一个数,再让CPU去做一次减法吧, 正好(~val)+1 <=> 256-val => val-256 <=> -((~val)+1)(~val是val的二进制按位取反), 按位取反对计算机来说那就so easy了。

所以我们要求一个负数的补码,根本不需要二进制按位取反再加1,计算机这么做因为它擅长这样的做法,但我们(至少是我)不擅长,我们擅长十进制加减法,那我们就用等价的另一种方法就行了,对于8 bits,求一个负数的补码,直接256加上这个负数就行了,得到的值就是对应的补码。

C语言深度剖析中有个题目:

int main()
{
    char a[1000] = {0};
    for(int i = 0; i < 1000; ++i) {
        a[i] = -1 - i;
    }
    printf("%d\n", strlen(a));

    return EXIT_SUCCESS;
}

问程序输出。

既然是问strlen的输出,而strlen是根据‘\0’(ASCII码是0)来计算C字符串(或者叫字符数组)的长度,a[i]的值从-1递减,从最上面那个图我们知道,它其实就是从255(对应-1)开始,按顺时针取值,-1 -> -128,之后就是127 -> 0,好了,0出现了,而0也就是字符’\0’本身是不算在长度内的,一圈正好256个,减去0,正好255个元素。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值