在计算机中,所有的信息都是二进制的,但我们看到的却是各种各样的字符。这是这么处理的呢?这个时候就需要使用一些编码方案。
当我们要把一些信息存储在计算机上时,需要对其进行编码转换为二进制信息进行存储,而需要显示这些信息时,就需要对其解码还原这些信息。需要注意的是,编码和解码要采用同样的规则。
所谓的编码就是用什么样的二进制信息表示什么样的对象,解码时根据映射关系还原为本来的信息。下面介绍一种计算机通常被采用的编码方案:ASCII编码。使用ASCII编码,首先要有映射表,部分字符映射关系如下:
0010 | 0011 | 0100 | 0101 | 0110 | 0111 | |
---|---|---|---|---|---|---|
0000 | 0 | @ | P | ` | p | |
0001 | ! | 1 | A | Q | a | q |
0010 | " | 2 | B | R | b | r |
0011 | # | 3 | C | S | c | s |
0100 | $ | 4 | D | T | d | t |
0101 | % | 5 | E | U | e | u |
0110 | & | 6 | F | V | f | v |
0111 | ' | 7 | G | W | g | w |
1000 | ( | 8 | H | X | h | x |
1001 | ) | 9 | I | Y | i | y |
1010 | * | : | J | Z | j | z |
1011 | + | ; | K | [ | k | { |
1100 | , | < | L | \ | l | | |
1101 | - | = | M | ] | m | } |
1110 | . | > | N | ^ | n | ~ |
1111 | / | ? | O | _ | o |
在实际应用中,对于字母的操作,可以根据这个映射关系,来对字母、大小写来判断,同时也可以实现大小写字母的相互转换,如对于大写字母 A,内存中实际存放的是 41H,对该数值进行+20H,就可以得到小写字母a。
只要分析和运用好字符和码表的关系,我们可以做很多实际的操作。例如,同样对于大小写字母装换,通过码表来看字母的大小写对应的二进制中的低四位是一样的,不同的是高四位的数值。对于大写字母来说,高四位的第三位为0(从左到右),对应的小写字母高四位中的第三位为1,其他位的数值一致。通过这个关系我们可以更好的对大小写进行转换。只需要把高四位中的第三位数值置为0,不管该字母是否为大写字母,最后都会变为大写字母。同样,把高四位中的第三位数值置为1,即可变为小写字母。
虽然知道了大小写的关系,可是怎么把某位上的数值置为0或者1呢?
对于硬件来说包含与门电路和或门电路,汇编中也相应的提供了逻辑与和逻辑或的指令:
and 操作对象1, 操作对象2
or 操作对象1, 操作对象2
如:
mov al, 11110000B
and al, 01111111B
执行后,al = 01110000B,即把最高位置为了0,其他位保持不变。
如:
mov al, 11110000B
or al, 00000001B
执行后,al=11110001B,即把最低位置为了1,其他位保持不变。
通过指令 and 和 or,我们就可以实现上述的大小写的转换,不用判断该字母是否为大写字母或小写字母。
既然知道了字符可以以二进制的方式存入内存中,可我们不可能记住所有的码表关系,那么应该怎么在内存中定义一个或多个字符呢?
前面已经说了汇编中定义数据的方式,同样我们可以使用 ‘…’ 的方式来定义字符,如:
db 'abcd'
这个时候,相当于定义了4个字节的数据分别存放在内存中,汇编编译器会自动把这些字符根据ASCII码转换为对应的二进制进行处理。
结合上面的码表和指令,现在就可以定义一个字符串并全部转为大写的功能:
assume cs:code, ds:data
data segment
db 'abcdefghijklmnop'
data ends
code segment
start:
mov ax, data
mov ds, ax
mov bx, 0
mov cx, 16
s: mov al, ds:[bx]
and al, 11011111B
mov ds:[bx], al
inc bx
loop s
mov ax, 4C00H
int 21H
code ends
end start
在这个编码中,出现了一个新指令 inc bx,该指令表示把 bx 的值加 1。
下面通过dosbox来运行看看内存中数据的情况吧:
- DEBUG装载程序后,通过R命令查看寄存器情况和要执行的第一行代码,从而可以看到数据所存放的段中,然后通过D命令来查看内存中我们定义的字符串,如下图所示:
- 继续执行程序,直到程序结束,并重新查看 04AE:0 后16个字节数据:
通过D命令可以发现,内存中定义的小写字母已全部转换为小写字母。
同样,对于大写字母转换为小写字母,可以通过逻辑或:OR 指令,把相应位的数值置为1即可。自己动手实践下吧。