以下过程用8位的有符号char表示数据。
1. 计算机为什么用补码存储整数
- 加法运行
计算机是按照二进制存储的,并且计算机只会做加法,不会减法。
首先看下加法,例如1+1=2
0000 0001
0000 0001
——————————
0000 0010
如果是1-1呢,因为计算机不会减法,会转换为1+(-1)。这就涉及到-1怎么表示了?如果用1000 0001表示-1进行如下计算
0000 0001
1000 0001
—————————
1000 0010 这个结果就表示-2,正确结果应该是0,说明这种表示方式不行。
- 引入补码
针对该问题,计算机的前辈们想到用补码的形式表示整数(内存中存储也是存的补码),正数的补码和原码一样,负数的补码的非符号位取反后加1。
按照这个规则,-1用补码表示为1000 0001(原码)——非符号为取反——>1111 1110——加1——>1111 1111.所以1+(-1)的计算过程如下:
0000 0001
1111 1111
——————————
10000 0000 这个结果表示0,正确。
2.-128怎么表示
大家都知道char的取值范围是-128~127,但是-128怎么表示呢?我们按照上面的补码规则推算一下:
1 1000 0000(用9位表示的原码)——非符号位取反——>1 0111 1111——加1——>1 1000 0000(补码)
由上可知,原码 1 1000 0000对应的补码还是自身。截断溢出的最高位后是1000 0000。
如果只8位的1000 0000,有人可能会认为是表示-0,实际是已经用0000 0000表示0了,1000 0000再表示0就重复了,那就约定表示-128,而且这样表示不会引入错误(至于之前的大佬怎么想出来的,我暂时还不清楚),例如-128+64,计算过程如下:
1000 0000
0100 0000
—————————
1100 0000 (补码形式)——减1——>1011 1111——非符号位取反——>1100 0000(原码形式,表示-64)
3.在Linux环境下,如何用gdb查看某个变量在内存中是按照补码形式存储的呢
如上图所示:
先用命令 p 查看变量val的内存地址,为0xffff1423.
再用命令 x 查看内存存储情况。
x /4xb 0xffff1423
4:表示查看4个字节的内存.
x:表示内存数据显示的格式,和C语言中的printf保持一致.
b:表示内存单位大小 ,b:1个字节,h:Halfwords(2个字节),w:Words(4个字节).
如上图,变量val在内存中存储为"ff ff ff f6" 确实是-10的补码形式.