#有符号数和无符号数

从内存中看有符号数和无符号数

首先我们通过汇编声明一些正数和负数如下图

mysql int 正负数_汇编


编译后的结果如下图

mysql int 正负数_nasm_02


很容易在这两幅图中间建立关系

前面的正数很好理解,十进制128对应的二进制数为10000000,对应的十六进制数为0x80;十进制0对应的二进制数为00000000,对应的十六进制数为0x00,我们为什么对此不感到新鲜,因为这非常自然。

真正的麻烦在于后面的负数,比如-1,编译的时候编译器会怎么做呢

编译器会做一个减法,因为-1=0-1,但是得做二进制的减法,用二进制0减去二进制数1,结果是

…1111111111111111111111111111111111

注意左边的省略号,因为在相减的过程中不断的向左边借位,这取决于你什么时候停止借位,再比如-2=0-2,在二进制的世界里,其实是二进制的0减去二进制的10,结果是

…1111111111111111111111111111111110

同样需要借位但是最右边的位为0;

在计算机中,数字保存在寄存器中,而在十六位处理器中,寄存器通常是8和16位的因此,十进制的-1表示成二进制是

11111111

即0xFF,十进制-2在寄存器AL中的二进制形式为

11111110

即0xFE,但如果是在16位寄存器比如AX中,则二进制形式是

1111111111111110

即0xFFFE。

有符号数和无符号数

我们知道,0xFF等于十进制数225,但现在又是十进制数-1,哪一个才是正确的呢?对比之前的编译结果,0x80即是十进制数-128,又是十进制数-128,到底哪一个正确呢?
    一个良好的解决方案就是计算机的数氛围两大类,有符号数和无符号数;
    在八位的字节运算中,无符号数的范围是00000000~11111111,即十进制的0~255;在 16 位的字运算中,无符号数的范围是 0000000000000000~1111111111111111,即十进制的 0~65535; 在将来要讲到的 32 位运算中,无符号数的范围是 000000000000000000000000 ~ 11111111111111111111111111111111,即十进制的 0~4294967295。很显然,我们以前使用的一直是 无符号数。
    相反地,有符号数是分正、负的,而且规定,数的正负要通过它的最高位来辨别。如果最高 位是 0,它就是正数;如果是 1,就是负数。如此一来,在 8 位的字节运算环境中,正数的范围 是 00000000~01111111,即十进制的 0~127;负数的范围是 10000000~11111111,即十进制的- 128~-1。

指令neg

neg指令带有一个操作数如下:
    neg al
    neg dx
    neg word [label_a] 
功能很简单,用0减去指令中指定的操作数,比如说:AL中的内容为00001000,执行neg al之后,al中的内容变为11111000,十进制数-8;
相应的既然已经知道了一个字节可以容纳的范围是十进制的-128~127,就不要这么写
mov al,-200
寄存器al只有8位,因此编译后-200将会截断,你可以这么写:
mov ax,-200
同样的规则也适用于db和dw

8位有符号数转换为12位

  • cbw
  • 没有操作数
  • 将寄存器al中的有符号数扩展到整个ax
  • cwd
  • 没有操作数
  • 将寄存器ax中的有符号数扩展到整个dx:ax

处理器中眼中的数据类型

假如寄存器中的内容为0xB23C,那么它到底是有符号数45628还是看成-19908?
    答案是,这是你的事,取决于你怎么看待他,答案是,这是你自己的事,取决于你怎么看待它。对于处理器的多数指令来说,执行的结果和 操作数的类型没有关系。换句话说,无论你是从无符号数的角度来看,还是从有符号数的角度来看, 指令的执行结果都是正确无误的。比如
        mov ah,al
   这条指令显然根本不考虑操作数的类型。再比如在这里,0xf0 的二进制形式是 11110000,它既可以解释为无符号数 240(十进制),也可以解 释为有符号数-16,毕竟它的符号位是 1。无论如何,inc 是加一指令,这条指令执行后,AH 中的 内容是二进制数 11110001,既是无符号数 241,也是有符号数-15。
    再考虑加法运算。比如
    mov ax,0x8c03
    add ax,0x05
    0x8c03 的二进制形式是 1000110000000011,既可以看做是无符号数 35843(十进制),也可以 看成是有符号数-29693(十进制)。在运算过程中,数的视角要统一,如果把 0x8c03 看成是无符 号数,那么 0x05 也是无符号数;如果 0x8c03 是有符号数,那么 0x05 也是有符号数。
    关键是运算后的结果。很幸运的是,add 指令同样适用于无符号数和有符号数。所以,这两条 指令执行后,AX 中的内容是 0x8c08,分别可以看成是无符号数 35848 和有符号数-29688。
再来考虑一下减法。考虑一下,如果要计算 10-3,这其实可以看成是 10+(-3)。因此,使 用以下三条指令就可以完成减法运算:
    mov ah,10
    mov al,-3
    add ah,al