?? 匯008.txt
字號:
例8.13 編寫一個創建子目錄的程序,具體要求如下:
1)、用鍵盤輸入一個目錄路徑名,若輸入的字符串為空,則程序運行結束;
2)、若目錄創建成功,顯示成功信息,否則,顯示創建失敗信息。
解:顯示解答
例8.14 編寫一個類似TYPE命令的程序,其要求如下:
1)、用鍵盤輸入文件名(可包含路徑),若輸入的字符串為空,則程序運行結束;
2)、若輸入的文件存在,則顯示其內容,否則,顯示文件不存在的信息。
解:顯示解答
8.3.7 內存管理的中斷功能
在C/C++語言環境中,若事先不知道數據的容量,那么,可通過動態申請空間的方法來解決數據的存儲問題,這種動態數據結構可用中斷21H所提供的存儲管理功能來實現。
中斷21H在內存管理方面所提供的主要功能如下:
48H——分配內存塊
49H——釋放內存塊
4AH——重定義內存塊的大小
58H——讀取/設置內存分配策略,其最基本的分配策略有三種:第一滿足、最好滿足和最后滿足
有關中斷功能的詳細描述和調用參數在此從略,需要查閱者可參閱附錄3之內存分配功能。
有關存儲分配策略的含義可參閱《操作系統》課程中“內存管理”部分的介紹。
8.3.8 讀取和設置中斷向量
中斷向量是系統用來存放中斷服務程序或系統參數的入口地址。在通常情況下,程序員不需要對中斷向量表作任何操作,但在開發程序時,若要為某種特殊需要而提供新的中斷處理程序時,則其就必須要操作中斷向量表。
1、讀取中斷向量
(1)、DOS功能調用的方法
DOS提供了用系統調用的方法來讀取中斷向量,其中斷21H之功能35H就能讀取指定中斷號的入口地址。其使用參數如下:
入口參數:AH=35H,AL=中斷號
出口參數:ES:BX=中斷處理程序的入口地址
例8.15 用功能調用的方法把中斷n的入口地址保存到雙字變量OldAddr中。
解:
……
OldAddr DD ?
……
MOV AL, n ;這里的n要用具體的中斷號來定
MOV AH, 35H
INT 21H
MOV word ptr OldAddr, BX
MOV word ptr OldAddr+2, ES ;把其入口地址保存在存儲單元中
……
(2)、直接訪問存儲單元的方法
由前面的圖8.2不難看出:中斷向量表是存儲在內存的第0段。若中斷號為n,那么,其入口地址在表內的偏移量為4n。
例8.16 用直接訪問存儲單元的方法把中斷n的入口地址保存到雙字變量OldAddr中。
解:
……
OldAddr DD ?
……
MOV AX, 0H
MOV ES, AX ;中斷向量表存儲在第0段內
MOV BX, 4*n
MOV AX, ES:[BX] ;讀取中斷入口地址的偏移量
MOV word ptr OldAddr, AX ;保存中斷入口地址的偏移量
MOV AX, ES:[BX+2] ;讀取中斷入口地址的段地址
MOV word ptr OldAddr+2, ES ;保存中斷入口地址的段地址
……
2、設置中斷向量
(1)、DOS功能調用的方法
中斷21H之功能25H可為指定的中斷號設置新的入口地址。其使用方法如下:
入口參數:AH=中斷號,DS:DX=中斷處理程序的入口地址
出口參數:無
例8.17 用功能調用的方法把子程序NewFunc設置為中斷n的中斷處理程序。
解:
……
NewFunc PROC
……
IRET ;注意其返回指令
NewFunc ENDP
……
MOV AX, SEG NewFunc
MOV DS, AX ;設置段地址寄存器
MOV DX, OFFSET NewFunc ;設置偏移量
MOV AL, n ;這里的n要用具體的中斷號來定
MOV AH, 25H
INT 21H
……
(2)、直接訪問存儲單元的方法
例8.18 用直接訪問存儲單元的方法把子程序NewFunc設置為中斷n的中斷處理程序。
解:
……
NewFunc PROC
NewFunc ……
IRET ;注意其返回指令
ENDP
……
MOV AX, 0H
MOV DS, AX
MOV BX, 4*n
CLI
MOV word ptr [BX], OFFSET NewFunc ;設置中斷處理程序的偏移量
MOV word ptr [BX+2], SEG NewFunc ;設置中斷處理程序的段地址
STI
……
在上面程序段中,指令CLI是一條值得注意的指令,它用來確保隨后二條MOV指令被連續執行而不被打斷。這是因為執行其第一條MOV指令后,原中斷向量表中的入口地址就被破壞了,這時,該入口地址既不是指向原處理程序,也不指向新處理程序。如果此刻正巧發生了該類型的中斷請求,那么,系統將轉向一個非法的位置。如果程序員能確信此時不會發生該類型的中斷請求,當然也就不必插入關中斷指令。
后面的指令STI是開中斷指令,它允許CPU響應其后的中斷請求。
3、修改中斷向量的步驟
前面,分別介紹了讀取和設置中斷入口地址的方法。在編程的實際過程中,若要修改某個具體的中斷處理程序時,一般需按下面幾步來完成:
1)、讀取指定中斷的中斷處理程序入口地址,并把它保存在存儲單元內;
2)、把用戶編寫的程序段設置為指定中斷的新處理程序;
3)、在用戶程序結束之前(或不需要新的處理程序時),把步驟1保存的入口地址恢復成處理該中斷的入口地址。
程序員按以上三步來編程,可保證:在其程序運行過程中,該指定的中斷將按新的處理程序來處理,程序結束后,中斷系統又恢復成原來的處理方式。所以,這種中斷向量的改變對其它程序或使用者來說是透明的,當然也就不會影響它們的正常運作。
以上三步具體化的形式如下:
……
INTNO EQU 40H ;假設被修改的中斷號
OldAddr DD ?
……
NewFunc PROC ;新的中斷處理程序
NewFunc ……
IRET
ENDP
……
MOV AL, INTNO
MOV AH, 35H
INT 21H
MOV word ptr OldAddr, BX
MOV word ptr OldAddr+2, ES ;步驟1:保存原入口地址
MOV DX, OFFSET NewFunc
MOV AX, SEG NewFunc
MOV DS, AX
MOV AL, INTNO
MOV AH, 25H
INT 21H ;步驟2:設置新的入口地址
……
;用戶編寫的主要程序
……
MOV DX, word ptr OldAddr
MOV DS, word ptr OldAddr+2 ;本指令與上一條指令能交換嗎?
MOV AL, INTNO
MOV AH, 25H
INT 21H ;步驟3:恢復原入口地址
……
END
8.4 習題
8.1、簡述中斷和子程序調用之間的主要區別?
8.2、為什么要區分IRET指令與RET指令?
8.3、編寫一個子程序,它可顯示以0結尾的字符串。子程序的入口參數DS:DX為待輸出字符串的首地址。
8.4、編寫一個子程序,用來讀入一個鍵,并在屏幕上按十六進制的形式顯示按鍵的擴展ASCII碼,如果按鍵為普通字符,則不顯示。
8.5、編寫一個程序,在屏幕的右下角閃爍顯示編程者自己的姓名,顯示顏色自定。
8.6、編寫一個把屏幕上顯示的字母經過大小寫轉換后再顯示的程序。
8.7、編寫一個程序,它把屏幕上的數字改位藍綠色背景的紅字。
8.8、編寫一個控制光標位置和形狀的程序,該程序具有以下功能:
1)、可用光標移動鍵↑、↓、←和→來移動光標;
2)、當光標已在第0列,且按'←'鍵時,光標定在上一行的最后一列;若已在屏幕的左上角,則光標不動,且給出響鈴;按'→'鍵時的邊界處理類似;
3)、當光標在第0行,且按'↑'鍵時,則光標不動,且給出響鈴;按'↓'鍵時的邊界處理類似;
4)、按Home或End鍵,則光標移到當前行的行首或行尾;
5)、若按下數字或字母鍵,則把該字符從當前位置依次顯示到屏幕頂(在新位置顯示字符時,原位置的符號被抹去);
6)、按Esc鍵,程序結束。
8.9、交換例8.5和8.6的畫線方法,編寫相應的子程序VLine和HLine,并驗證之。
8.10、假設顯示器的顯示模式設定為12H,編寫實現下列功能的程序:
1)、在屏幕中間從上到下顯示一條明亮的藍色線,線寬為1個像素;
2)、在屏幕底下橫向畫一條綠色線,線寬為2個像素;
3)、在屏幕上垂直顯示16種顏色,每種顏色寬40個像素;
4)、設定屏幕背景為白色,在屏幕中間畫一條青色線,線寬為10個像素。
8.11、對于256色,320X200的顯示模式需要多少個字節的內存存放一屏信息?
8.12、為什么在顯示數據時必須關閉鼠標?
8.13、編寫程序,檢測計算機是否已安裝了鼠標,并以顯示Yes/No來表示檢測結果。
8.14、編寫程序,顯示鼠標的按鍵,若按左鍵,顯示"Left",若按右鍵,顯示"Right",按Esc鍵,程序結束。
8.15、編寫一個程序,在圖形模式下,打開鼠標,并顯示鼠標的位置。
8.16、編寫一個程序,顯示驅動器C根目錄下所有EXE文件。提示:用通配符"*.exe"來查找與此匹配的文件名,找到后,顯示之。
8.17、編寫一個程序,顯示驅動器C根目錄下的所有子目錄。
8.18、編寫一個程序,設置指定目錄下的所有文件為只讀文件。
8.19、編寫一個程序,創建一個隱含文件Data.TXT。
8.20、編寫一個程序,把鍵盤上輸入寫入文件File.dat中,類似以下DOS命令:
COPY con File.dat
8.21、使用哪個DOS功能可讀取中斷向量地址,哪個DOS功能可把新的中斷服務程序地址設置為指定中斷的入口地址。
8.22、編寫一個程序,在程序開始運行時,把中斷向量表保存到程序的數據段中,在程序結束前把數據段中的備份恢復到系統中去。
8.23、把下列C語言的子程序改寫成匯編語言子程序。
1)、取當前光標的位置,并分別存入變量x和y中
get_cursor(int *x, int *y)
{union REGS in, out;
in.h.ah = 3; in.h.bh = 0;
int86(0x10, &in, &out);
*x = out.h.dh; *y = out.h.dl;
}
2)、把光標設置在(row, col)位置
locate(int row, int col)
{union REGS in, out;
in.h.ah = 2; in.h.bh = 0;
in.h.dh = row; in.h.dl = col;
int86(0x10, &in, &out);
}
3)、在(row, col)位置顯示字符串string
disp_string(int row, int col, char string[])
{struct REGPACK in, out;
int x, y;
get_cursor(&x, &y);
locate(row, col);
in.r_ds = FP_SEG(string);
in.r_dx = FP_OFF(string);
in.r_ax = 0x900;
intr(0x21, &in);
locate(x, y);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -