一、關於串操作的一些說明:
雖然我們知道,在高級語言裏面,串 和 一般的數據的標識符會有一些不一樣(比如C++ 裏面整形的 int 以及字符串的 string )但是,在底層語言裏面,他們類型其實都是一樣的二進制數。只不過串是一個數據塊。我們用下圖說明一下:
那麼, 在執行串操作之前,我們需要確定以下的幾件事情:
- 串所在的區域,串的首地址(這裏的串包括源串和目標串)
- 串的長度
- 串操作的方向,這個我們用一張圖來理解:
如果橫向的藍色箭頭表示的是源串首,假如串操作的方向是 由低地址向高地址,那麼實際上要操作的串就是下方的一塊區域;但是如果方向是 由高地址向低地址,那麼要操作的串就應該是上方的一塊區域。二者的串本身完全不一樣!
- 串操作的指令之前可以加上一個重複前綴。
下面,我們一一來解釋以下:
【1】首先是串的位置:我們的操作對象是 源串和目標串。其中,源串默認的段首地址存放在 (數據段裏面),串首地址存放在 ,即:。(其中 可以使用段超越變成其他段)
而目標串它的段地址默認是在附加段 ,串首地址在 裏面(注意 不允許被段超越!)
【2】關於串的長度,我們會將串的長度值存放在 裏面。在使用串操作指令之前,我們需要給 賦初值
【3】關於串操作的方向,我們使用狀態標識裏面的 來表示:如果 表示的是串操作從低地址向高地址執行;如果 ,那麼表示從高地址向低地址執行。同樣地,我們也要在使用串操作指令之前,給 賦初值: 表示將 清零; 表示將 置1
【4】關於串操作指令前面的循環前綴(這是串操作指令所特有的),重複前綴可以分爲無條件前綴和條件前綴。其中,無條件前綴我們用 表示,它的意思是:只要當 的情況下,我們就一直執行 後面跟着的語句 我們可以看到,因爲是無條件地反覆執行,因此,後面常常跟串傳輸類指令
而對於條件前綴,我們分兩種:
(1)REPZ,或者說 REPE(都行):它的意思是"相等則重複“當 ,且時,重複執行
(2)REPNZ,或者說 REPNE:它的意思是“不相等則重複”,即當 ,且時重複執行
我們可以看到,對於條件前綴,後面常常跟串運算類指令
1.1 串操作指令執行的一般流程
我們用下圖說明:
其中,我們可以看到流程圖主要分成了兩塊:左邊的四個步驟,我們稱之爲初始化。這裏需要特別說明:串操作指令中,每操作完一個字節或者一個字之後,串首指針是指令自動更改的。不需要我們手動設置。而上圖幾乎是所有串操作指令執行都需要經過的流程圖,我們發現:在每操作完一個字節或者一個字之後,並不是立刻就去判斷是不是已經完成了所有操作,而是在修改完地址指針之和,還需要經過修改串長度(這需要我們自己寫程序控制)的這個操作之後,纔到判斷。
下面,我再把這個圖分模塊畫一下:
那麼,試想一下:假如我們的串操作方向是 DF = 0,而且是一個串傳輸指令;那麼在所有數據傳輸完畢之後,串首指針應該是在串尾的後一位!
二、正題——串操作指令
2.1 串傳送指令 MOVS
首先是串傳送:,更具體地說,應該分成兩種: 和
顧名思義就是傳送1個字節(也就是8位)的串;而 則是傳送 1個字的串。
我們看一個例子學習它的用法:
使用 指令,將200個字節數據從內存數據段 MEM1 爲首地址的區域送到一個邏輯段 MEM2
爲首地址的區域:(我們下面給出程序的分析):
LEA SI, MEM1 //這句話的意思是給源串的串首賦初值(要賦值給SI寄存器)
LEA DI MEM2 //這句話也是給目標串的串首地址賦初值(要賦值給 DI 寄存器)
MOV CX 200 //給 串的長度賦初值(要賦值給 CX)
CLD //令 DF = 0,說明是從低地址向高地址執行
REP MOVSB //無條件重複:只要 CX ≠0 就一直執行串的傳輸
HLT //當REP跳出來了,就結束
當然也是可以用 的,這樣的話,我們的 CX 就要賦初值爲 100 了,因此 一次操作16位
那麼,假如我們想要驗證我們傳輸的串對不對,那麼就需要將這兩個串進行比較。因此就引出了串比較指令:
2.2 串比較指令 CMPS
同樣地,CMPS 也分爲:CMPSB, CMPSW。它執行的是啥呢?—— 目標串 - 源串,但是結果並不返回目標串。也即是實現兩串的比較。
對於串比較指令,我們一般在它前面加條件前綴。
那麼,依舊是剛剛的例子,我們在傳輸完了 200 個字節的串之後,想要檢測一下是否正確傳輸,我們就需要比較兩個串了:下面是程序分析:
LEA SI, MEM1
LEA DI MEM2
MOV CX, 200
CLD //上面四條語句全都是初始化
REPE CMPSB
JZ STOP //JZ 表示當 ZF = 1 時執行跳轉,執行到這裏如果ZF仍然爲1說明兩串一樣
DEC SI //完成SI的自減,回顧上面的流程圖,SI現在是在串低的後一位
MOV AL, [SI]
MOV BX, SI
STOP: HLT
首先,我們明確一件事情:REPE 的意思是相同即重複(,且 ),也就是說當比較的串一樣時,就繼續比。那麼 REPE 退出的情況有什麼呢?
- CX = 0(說明比完了,那麼就是兩個串完全一樣)
- ,但是 (說明在中間有兩個串不一樣的地方了)
JZ 表示當 時執行跳轉,跳轉到 STOP
2.3 串掃描指令
我們常常使用的是 或 。當我們使用 時,源操作數是不用寫出來的,但是要在程序的前面聲明。(注意:使用 時,源操作數是 或者 。當使用 時,一次操作一個字節單元,源操作數就是 )
另外,說一下 都幹了什麼:
我們以 爲例,它執行的是將 裏面存放的字節依次 和串內的每一個字節單元相減,但是結果不返回,影響標誌位 ,用於搜索串裏面有沒有哪個字節單元的內容和 的一樣。
舉一個例子:在 ES段中從 2000H 單元開始存放了 10 個字符,尋找其中有沒有字符 ‘A’,若有則記錄搜索次數,將搜索次數寫入 DATA1 單元,並將 ‘A’ 寫入 DATA2 單元。
首先,我們要明確一件事情:目標串地址在 ES:DI 裏面。
MOV DI, 2000H //先給DI 賦值
MOV BX, DI //地址備份,用於後面計算搜索次數
MOV CX, 10 //因爲如果採用SCASB,那麼就是一個字節一個字節搜索,10次
CLD
REPNZ SCASB //“若不相等則重複”,如果不相等,即ZF = 0 ,那麼就一直搜索
JZ FOUND //若 ZF = 1 就跳轉到 FOUND(ZF=1 說明找到一樣的了)
MOV DI, 0
JMP DONE
FOUND: DEC DI //因爲 DI 是先自增之後才進入判斷的,所以在跳出之後DI 會在 'A' 的後一個單元
MOV DATA1, DI
INC DC
SUB DI, BX //計算搜索次數
DONE: MOV DATA2,DI
HLT
2.4 串加載與串存儲
【1】首先是串加載,我們用 或 ,既然是 加載,那麼就是將串中的數據裝載到某個地方,因此,在 或 中,串是作爲源操作數的,地址在
如果使用的是 ,那麼它執行的操作是將數據段中地址爲 的單元裝入 ;
如果使用的是 ,那麼它執行的操作是將數據段中地址爲 的單元裝入 ;
【2】下面是串存儲,我們用 或 ,既然是存儲,就是把某個內容存儲進串裏。因此,此時串就作爲目標串,地址爲:
如果使用的是 ,那麼它執行的是將 裏面的內容存儲進 內
如果使用的是 ,那麼它執行的是將 裏面的內容存儲進 內
注意:在串加載與串存儲中,是已經限定了 的!