本节内容:整数的编码规则。
■数据的编码规则:计算机的二进制数对于计算机本身而言仅仅表示0和1。人们按照不同的编码规则赋予二进制数不同的含义。整数的编码规则分为有符号整数和无符号整数。
■数据的存储规则:x86计算机以字节为单位,按照高高低低的原则存储数据,即高地址存储数据的高位值,低地址存储数据的低位值,称之为小端存储规则。反之则称为大端存储规则。
■无符号数的编码规则:无符号整数全部是正数,所有数据位都表示数值,没有符号位。
■有符号数的编码规则:最高位为符号位,“0”表示正数,“1”表示负数。
在前面的章节中,我们知道了在电子计算机内存储的都是二进制数0和1。计算机只是一台机器,并不能识别各种不同类型编码格式的数据。数据的编码格式是我们人为定义的。
举例
下面的数据表示什么意思?
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
文本文件中这个数据可能表示逗号,exe程序中也可能是一条指令,也有可能是一个数字55H。不同的文件有不同的编码规则,对应不同的含义。比如视频、图片、文本等等。
有了指定的数据编码规则之后,我们还需要考虑以什么样的方式将数据存储到计算机的内存中。在x86计算机中,数据是以小端方式存储的,低地址存储数据的低字节,高地址存储数据的高字节,即高高低低的存储方式。而在网络传输中,数据则以大端方式存储的,与小端存储方式相反,低地址存储数据的高字节,高地址存储数据的低字节。下面我们来做实验,验证x86计算机中的小端存储方式。
动手实验5:x86计算机中的小端存储方式
mov eax,0x12345678这条指令的含义是将一个32位的16进制数存入eax寄存器。我们做一个实验,将这条指令写入DTdebug调试器,在调试器中观察如何存储0x12345678。
第一步:打开DTdebug调试器,将IPMSG200.exe拖入调试器中。
第二步:左上角反汇编窗口双击第一条汇编指令,弹出的对话框中填写mov eax,0x12345678指令,点击汇编选项或者直接回车。如图2-14所示,左侧硬编码中的数据为78-56-34-12,与我们正常书写的顺序相反。
图2-14 反汇编窗口观察小端存储模式
第三步:接下来,鼠标点入左下角内存窗口,键盘输入CTRL+G,弹出对话框窗口中输入该条指令的起始地址775a1c37,如图2-15所示:
图2-15 跳转到内存地址
第四步:观察内存窗口,如图2-16所示:在低地址775a1c37处存储低字节数据78,以此类推,地址775a1c38处存储56,地址775a1c39处存储34,高地址775a1c3a处存储高字节数据12,与图2-14所示的硬编码中的小端存储方式相同。
无符号整数编码规则:无符号整数全部都是正数,是什么就存什么,没有符号位。
举例
无符号整数9AH,数据宽度为32位。
低位 |
1 |
0 |
0 |
1 |
1 |
0 |
1 |
0 |
....... |
0 |
高位 |
十六进制数表示:0x0000009AH。
二进制数表示:0000 0000 0000 0000 0000 0000 1001 1010B。
注意:当我们表述或定义一个整数时,一定要表明数据的宽度。
有符号整数编码规则:最高位为符号位,“0”表示正数,“1”表示负数。
举例
有符号整数1AH,数据宽度为32位
低位 |
0 |
0 |
0 |
1 |
1 |
0 |
1 |
0 |
....... |
0 |
高位 |
正数:符号位为0。
十六进制数表示:0x0000001A。
二进制数表示:00000000 00000000 00000000 0001 1010。
负数:符号位为1。
十六进制数表示:0x8000001A。
二进制数表示:10000000 00000000 00000000 0001 1010。
图2-17 无符号整数和有符号整数
如图2-17所示,无符号整数常见的三种数据类型为字、双字和四字。所有数据位均表示整数数值,并且都是正整数。有符号整数常见的三种数据类型为字、双字和四字。最高位表示符号位,最高位为0,表示有符号正整数,最高位为1,表示有符号负整数,其余各位表示整数值。
■以圆的形式表现数据的存储范围
●字节(Byte) :0~0xF 4位
图2-18 4位整数的存储范围
如图2-18所示,4位无符号整数的数据范围:0 1 2 3 4 ......F (10进制0 ~15)。
4位有符号整数的数据范围:(-8 ~ 7)。
正数:0,1,2,3,4,5,6,7 (10进制0 ~7)。
负数:F,E,D,C,B,A,9,8 。
F= -1( 10进制-1~ - 8 )。
●字节(Byte) :0~0xFF 8位
图2-19 8位整数的存储范围
如图2-19所示,8位无符号整数数据范围:0 1 2 3 4 ......FF(10进制0~255)。
8位有符号整数数据范围:(-128~127)。
正数:0......3F,40......7F (10进制0 ~127)。
负数:FF......C0,BF......8 0。
FF= -1( 10进制-1~ - 128 )。
●字(Word) :0~0xFFFF 16位
图2-20 16位整数的存储范围
如图2-20所示,16位无符号整数数据范围:0 1 2 3 ......FFFF(10进制0~216-1)。
16位有符号整数数据范围:(-215~215 -1)。
正数:0....3FFF,4000...7FFF (10进制0 ~215 -1)。
负数:FFFF......C000,BFFF......8000
FFFF= -1( 10进制-1~ - 215 )
●双字(Dword) :0~0xFFFFFFFF 32位
图2-21 32位整数的存储范围
如图2-21所示,32位无符号整数数据范围:0 1 2 3 …FFFFFFFF(10进制0~232-1)。
32位有符号整数数据范围:(-231~231 -1)。
正数:0...3FFFFFFF,40000000...7FFFFFFF(10进制0 ~231 -1)。
负数:FFFFFFFF...C0000000,BFFFFFFF...80000000。
FFFFFFFF= -1( 10进制-1~ - 231 )。
在8086 16位汇编语言中,程序员根据无符号整数和有符号整数的指令来确定指令操作数为有符号整数还是无符号整数。无符号指令有JB、JA、SHR等,有符号指令有JL、JG、SAR等。80386以上32位或64位汇编语言,C\C++等高级语言中,程序员在数据定义时明确整数的编码格式为有符号整数还是无符号整数。如32位汇编语言无符号整数数据类型Byte、Word、Dword等,有符号整数数据类型SByte、SWord、SDword等。
举例
■16位汇编语句
var1 db 1 ;数据类型db,并未说明变量var1是有符号数还是无符号数
cmp al,var1 ;比较无符号整数大小
JB next1 ;JB无符号数指令,当无符号数al小于无符号数var1时,跳转到next1地址
Next1:
…
var1 db 1 ;数据类型定义db,并未说明变量var1是有符号数还是无符号数
Cmp al, var1 ;比较有符号整数大小
JL next2 ;JL有符号数指令,当有符号数al小于有符号数var1时,跳转到next2地址
Next2:
…
■32位汇编语句
var2 byte 1 ;数据类型byte,说明变量var2是无符号数
cmp al,var2 ;比较无符号整数大小
JB next1 ;只能使用无符号数指令JB
Next1:
…
var2 sbyte 1 ;数据类型sbyte,说明变量var2是有符号数
cmp al,var2 ;比较无符号整数大小
JL next1 ;只能使用有符号数指令JL
Next1:
…
■C语言
usigned char var3; //无符号整数,数据宽度8位
usigned char var4;
signed char var5; //有符号整数,数据宽度8位
signed char var6;
If (var3 < var4) //比较无符号整数var3,var4大小
If(var5 > var6) //比较有符号整数var5,var6大小
…
else
…
注意
汇编语言中并不会严格检查有符号或无符号数据类型,只要数据类型的宽度一致,编译器并不会报错。即上述示例中无论使用JB指令还是JL指令,数据宽度都是8位。编译都可以通过,具体定义为哪种数据类型,由写这条语句的程序员来决定。
但是在C/C++等高级语言中,编译器会严格检查数据类型,如果数据类型错误,通常编译无法通过。
我们将在后续的课程中学习汇编16位汇编语言、32位汇编语言和C语言的语法规则。
总结
1.无符号整数和有符号整数是计算机整数编码规则。
2.无符号数都是正整数,没有符号位,所有数据位均表示整数值。
3.有符号整数最高位为符号位,分为正整数(最高位为0)和负整数(最高位为1)。
4.如果存储的数据超过最大宽度,那么多余的数据将被丢弃!
5.无符号整数和有符号整数的数据类型表示数据宽度,由程序员定义,与计算机无关。
6.x86 CPU只进行整数的算术逻辑运算。浮点数(数学中的实数)由x87处理器处理。我们将在第四十一章浮点处理器及其指令编码中详细讲述。
本文摘自编程达人系列教材《X86汇编语言基础教程》。