iT邦幫忙

2019 iT 邦幫忙鐵人賽

4
Software Development

8086下16位元DOS組合語言學習筆記系列 第 12

[Day12] 使用 AND、OR 進行字母大小寫轉換

AND 指令

進行 AND 運算會有下列四種結果,只有當兩數都為真時,結果才為真

  運算式     結果
---------|--------
 1 AND 1 |    1
 1 AND 0 |    0
 0 AND 1 |    0
 0 AND 0 |    0

AND 指令會對暫存器的所有位元進行 AND 運算。

mov al, 00000111B
and al, 00000011B   ; 結果為 00000011

觀察 AND 可以發現兩個特性:

  1. 任何數 AND 1 等於任何數
  2. 任何數 AND 0 等於 0

利用這兩個特性可以將數據的 指定位元設為 0 而其餘不變

; 將 al 的第 5 位設為 0 其餘不變
mov al, 00111000B
and al, 11101111B   ; 結果為 00101000

OR 指令

進行 OR 運算會有下列四種結果,只要兩數其中一個為真,結果就為真

  運算式     結果
---------|--------
 1 OR 1  |    1
 1 OR 0  |    1
 0 OR 1  |    1
 0 OR 0  |    0

OR 指令會對暫存器的所有位元進行 OR 運算。

mov al, 00000111B
or  al, 00000011B   ; 結果為 00000111B

OR 也有類似的兩個特性:

  1. 任何數 OR 0 等於任何數
  2. 任何數 OR 1 等於 1

利用這兩個特性可以將數據的 指定位元設為 1 而其餘不變

; 將 al 的第 5 位設為 1 其餘不變
mov al, 00000110B
and al, 00010000B   ; 結果為 00010110

大小寫字母的 ASCII

ASCII 編碼大家應該都很熟悉,這裡就不講太多直接來看字母的 ASCII,可以發現大寫字母加上 100000b 就變成小寫字母,小寫字母減去 100000b 就變成大寫字母,因此可以利用 第6個位元 進行字母的大小寫轉換。

 大寫字母   十進制      二進制     小寫字母   十進制     二進制
---------|--------|------------|---------|--------|------------
    A    |   65   |  01000001  |    a    |   97   |  01100001
    B    |   66   |  01000010  |    b    |   98   |  01100010
    C    |   67   |  01000011  |    c    |   99   |  01100011
    D    |   68   |  01000100  |    d    |  100   |  01100100
    E    |   69   |  01000101  |    e    |  101   |  01100101

可以使用 AND 指令將字母轉換為大寫:

and al 11011111B

可以使用 OR 指令將字母轉換為小寫:

or al 00100000B

組合語言中陣列的應用 [常數+bx]

C 語言中的陣列:

char a[5] = "abcde";
char b[5] = "12345";

組合語言中陣列可以這樣使用:

data segment
    db 'a','b','c','d','e'
    db '1','2','3','4','5'
data ends

code segment
start:
    mov ax, data
    mov ds, ax  
    
    mov bx, 0   
    mov cx, 5   
s:  
    mov ax, [0+bx]   ; 等於 a[bx]
    mov ax, [5+bx]   ; 等於 b[bx]
    inc bx   
    loop s

code ends
end start

題目

按照慣例最後出個題目讓大家玩玩,題目如下:

將陣列 a 的字母放入進陣列 b,並將大寫轉為小寫,小寫轉為大寫。
例如: aBcDe -> AbCdE

data segment
    db 'a','B','c','D','e'   ; 陣列 a
    db '0','0','0','0','0'   ; 陣列 b
data ends

解答:

assume cs:code, ds:data
data segment
    db 'a','B','c','D','e'   ; 陣列 a
    db '0','0','0','0','0'   ; 陣列 b
data ends

code segment
start:
    mov ax, data        ; 將 data 的地址放到 ax 暫存器
    mov ds, ax          ; 將 ax 的值放到 ds 暫存器

    mov bx, 0           ; 設置 bx 指向數據段的第一個位置
    mov cx, 5           ; 指定迴圈次數為5
s:  
    mov al, [0+bx]      ; 取出陣列 a 的字母放進 al
    xor al, 00100000b   ; 字母轉換大小寫
    mov [5+bx], al      ; 將結果放進陣列 b

    inc bx              ; 將 bx 累加一
    loop s

    mov ax, 4c00h       ; 退出程式
    int 21h             ; 調用系統功能
code ends
end start

結果:

https://ithelp.ithome.com.tw/upload/images/20181126/20106865L8oibvfw1b.jpg


XOR 指令

解答中用到了 XOR 指令,那就順便補充一下,
進行 XOR 運算時,左右兩數,一個為真,另一個為假時,結果才為真

  運算式     結果
---------|--------
 1 XOR 1 |    0
 1 XOR 0 |    1
 0 XOR 1 |    1
 0 XOR 0 |    0

XOR 有兩個特性:

  1. a XOR 0 等於 a
  2. a XOR a 等於 0

回到上面的題目
大寫字母 01000001 進行 xor 運算後,0 xor 1 等於 1,大寫轉成小寫
小寫字母 01100001 進行 xor 運算後,1 xor 1 等於 0,小寫轉成大寫
而 XOR 的第一個特性 a XOR 0 等於 a,告訴我們不會影響其他位的值
因此利用 XOR 指令就能將大寫轉小寫、小寫轉大寫

結語

總結一下:

  • 如果想將所有字母轉成大寫可以使用 AND 運算
  • 如果想將所有字母轉成小寫可以使用 OR 運算
  • 如果想將大寫轉小寫、小寫轉大寫可以使用 XOR 運算

好久沒發文了,今天就到這裡摟,感謝大家觀看。


上一篇
[Day11] 程式分段和字母反轉 + 斷賽感言
系列文
8086下16位元DOS組合語言學習筆記12

尚未有邦友留言

立即登入留言