table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
pre {
background-color: #f8f8f8;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}
142、编写一个名为 mPrintChar 的宏,用于在屏幕上显示单个字符。它应该有两个参数:第一个参数指定要显示的字符,第二个参数指定该字符应重复显示的次数。假设存在一个函数 WriteChar 用于在控制台显示单个字符,以下是一个示例调用:mPrintChar ‘X’,20
以下是实现
mPrintChar
宏的代码:
mPrintChar MACRO char, count
push ecx
mov ecx, count
L1:
push eax
mov al, char
call WriteChar
pop eax
loop L1
pop ecx
ENDM
该宏通过循环,根据传入的重复次数,多次调用
WriteChar
函数来显示指定字符。
143、给出调用 mWriteString 宏的语句 mWriteStr namePrompt 所生成的展开代码
push edx
mov edx, OFFSET namePrompt
call WriteString
pop edx
144、在使用标签的宏中会用到 LOCAL 指令。a. 编写一个使用该指令的宏。b. 使用这个宏,说明如果不使用该指令会出现的问题。
a. 以下是一个使用
LOCAL
指令的宏示例:
makeString MACRO text
LOCAL string
.data
string BYTE text,0
ENDM
b. 如果不使用
LOCAL
指令,当多次调用宏时,汇编器不允许两个标签有相同的名称,会导致错误。例如:
makeString "Hello"
.data
string BYTE "Hello",0
makeString "Goodbye"
.data
string BYTE "Goodbye",0
这里会出现错误,因为两次使用了相同的标签名
string
。而使用
LOCAL
指令后,预处理器会将标签名转换为唯一标识符,如第一次调用宏生成的标签可能是
??0000
,第二次是
??0001
,避免了标签重定义问题。
145、给出一个宏参数具有默认参数初始化器的示例。
例如,
mWriteln
宏可以提供一个包含单个空格的字符串作为其默认参数。其定义如下:
mWriteln MACRO text:=<" ">
mWrite text
call Crlf
ENDM
如果调用时没有参数,它仍会打印一个空格并换行。
146、编写一个使用IF、ELSE和ENDIF指令的简短示例。
示例代码如下:
.data
X DWORD 0
op1 DWORD 2 ; test data
op2 DWORD 4 ; test data
op3 DWORD 5 ; test data
.code
mov eax,op1
mov ebx,op2
mov ecx,op3
.WHILE eax < ebx
inc eax
.IF eax == ecx
mov X,2
.ELSE
mov X,3
.ENDIF
.ENDW
147、假设以下 mLocate 宏定义:mLocate MACRO xval,yval IF xval LT 0 ;; xval < 0? EXITM ;; if so, exit ENDIF IF yval LT 0 ;; yval < 0? EXITM ;; if so, exit ENDIF mov bx,0 ;; video page 0 mov ah,2 ;; locate cursor mov dh,yval mov dl,xval int 10h ;; call the BIOS ENDM 显示以下每条语句展开宏时预处理器生成的源代码:.data row BYTE 15 col BYTE 60.code mLocate -2,20 mLocate 10,20 mLocate col,row
对于
mLocate -2,20
:无代码生成,因为
xval = -2 < 0
,宏执行
EXITM
退出。
对于
mLocate 10,20
:
asm
mov bx,0
mov ah,2
mov dh,20
mov dl,10
int 10h
对于
mLocate col,row
:
asm
mov bx,0
mov ah,2
mov dh,row
mov dl,col
int 10h
148、创建一个宏,该宏等待用户按键并返回按下的键。该宏应包含用于存储 ASCII 码和键盘扫描码的参数。编写一个程序来测试你的宏。例如,以下代码等待按键;返回时,两个参数将包含 ASCII 码和扫描码:.data ascii BYTE? scan BYTE?.code mReadkey ascii, scan
下面是实现该功能的宏及测试程序代码:
; mReadkey 宏定义
mReadkey MACRO ascii, scan
call ReadChar
mov ascii, al
mov scan, ah
ENDM
; 测试程序
INCLUDE Irvine32.inc
.data
ascii BYTE ?
scan BYTE ?
.code
main PROC
mReadkey ascii, scan ; 这里可以添加代码来验证 ascii 和 scan 的值,例如显示它们
exit
main ENDP
END main
上述代码定义了
mReadkey
宏,它调用
ReadChar
函数获取按键信息,并将 ASCII 码和扫描码分别存储到传入的参数中。测试程序调用该宏并等待按键,之后可以添加代码来验证存储的值。
149、创建一个宏,该宏将一个以空字符结尾的字符串以给定的文本颜色写入控制台。宏参数应包括字符串名称和颜色。调用一个能设置文本颜色的函数(假设为 SetTextColor)。编写一个程序,使用不同颜色的多个字符串来测试你的宏。示例调用:.data myString db “Here is my string”,0.code mWritestring myString, white
以下是实现该功能的代码示例:
.data
myString1 db "String in red",0
myString2 db "String in blue",0
red EQU 4
blue EQU 1
.code
mWritestring MACRO str, color
pushad
mov eax, color
call SetTextColor
mov edx, OFFSET str
call WriteString
popad
ENDM
main PROC
mWritestring myString1, red
mWritestring myString2, blue
INVOKE ExitProcess,0
main ENDP
END main
上述代码定义了一个名为
mWritestring
的宏,它接受一个字符串和颜色作为参数,通过调用
SetTextColor
设置颜色,然后使用
WriteString
输出字符串。在主程序中,调用该宏两次,分别输出不同颜色的字符串。
150、编写一个名为 mMove32 的宏,该宏接收两个 32 位内存操作数。宏应将源操作数移动到目标操作数。编写一个程序来测试你的宏。
以下是实现
mMove32
宏及测试程序的代码示例(使用 MASM 语法):
; 定义 mMove32 宏
mMove32 MACRO source, destination
MOV EAX, source
MOV destination, EAX
ENDM
; 测试程序
.MODEL SMALL
.STACK 100H
.DATA
sourceOperand DWORD 12345678h
destinationOperand DWORD ?
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
; 调用 mMove32 宏
mMove32 sourceOperand, destinationOperand
; 程序结束
MOV AH, 4CH
INT 21H
MAIN ENDP
END MAIN
上述代码定义了
mMove32
宏,它将源操作数移动到目标操作数。测试程序中,我们定义了一个源操作数和一个目标操作数,然后调用
mMove32
宏进行数据移动。最后程序正常结束。
151、创建一个宏,该宏等待按键输入并返回按下的键。宏应包含用于存储 ASCII 码和键盘扫描码的参数。编写一个程序来测试你的宏。例如,以下代码等待按键输入;返回时,两个参数将包含 ASCII 码和扫描码:.data ascii BYTE ? scan BYTE ? .code mReadkey ascii, scan
以下是实现该功能的代码:
; mReadkey 宏定义
mReadkey MACRO ascii, scan
call ReadChar
mov ascii, al
mov scan, ah
ENDM
; 测试程序
INCLUDE Irvine32.inc
.data
ascii BYTE ?
scan BYTE ?
.code
main PROC
mReadkey ascii, scan ; 可以在这里添加代码来验证 ascii 和 scan 的值
exit
main ENDP
END main
上述代码定义了
mReadkey
宏,它调用
ReadChar
函数获取按键的 ASCII 码和扫描码,并将其分别存储到传入的参数中。然后编写了一个简单的测试程序来调用这个宏。
152、创建一个宏,该宏能将一个以空字符结尾的字符串以指定的文本颜色写入控制台。宏的参数应包括字符串名称和颜色。编写一个程序,用不同颜色的多个字符串来测试你的宏。示例调用:.data myString db “Here is my string”,0 .code mWritestring myString, white
以下是实现该功能的代码示例:
INCLUDE Irvine32.inc
; 定义mWritestringAttr宏
mWritestringAttr MACRO stringName, color
push eax
push edx
mov eax, color
call SetTextColor
mov edx, OFFSET stringName
call WriteString
pop edx
pop eax
ENDM
.data
myString1 db "This is a red string",0
myString2 db "This is a green string",0
myString3 db "This is a blue string",0
.code
main PROC
; 测试mWritestringAttr宏
mWritestringAttr myString1, red
call Crlf
mWritestringAttr myString2, green
call Crlf
mWritestringAttr myString3, blue
call Crlf
INVOKE ExitProcess,0
main ENDP
END main
上述代码定义了
mWritestringAttr
宏,它接受字符串名称和颜色作为参数。在宏内部,先调用
SetTextColor
设置文本颜色,然后调用
WriteString
输出字符串。主程序中使用不同颜色的字符串对宏进行了测试。
153、编写一个名为 mMove32 的宏,该宏接收两个 32 位内存操作数。宏应将源操作数移动到目标操作数。编写一个程序来测试你的宏。
以下是 mMove32 宏的实现和测试程序示例(使用 MASM 语法):
; 定义 mMove32 宏
mMove32 MACRO dest, src
mov eax, src
mov dest, eax
ENDM
; 测试程序
.MODEL SMALL
.STACK 100H
.DATA
source DWORD 12345678h
destination DWORD ?
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
; 调用 mMove32 宏
mMove32 destination, source
; 退出程序
MOV AH, 4CH
INT 21H
MAIN ENDP
END MAIN
上述代码中,定义了 mMove32 宏,它将源操作数的值移动到目标操作数。测试程序创建了一个源操作数和一个目标操作数,调用宏进行数据移动,最后退出程序。
154、模拟一个人在校园里进行随机游走的过程,要求程序在随机的某个时间点,将手机丢在这个人当时所在的位置,且每次运行程序时,手机丢失的时间点和位置都不同。
此为编程任务描述,需编写程序模拟人随机游走过程,在随机时间点让人丢失手机,每次运行程序手机丢失时间和位置不同。
155、哪个Win32函数返回标准输入的句柄?
`GetStdHandle` 函数返回标准输入、输出或错误输出的控制台流句柄。当 `nStdHandle` 参数为 `STD_INPUT_HANDLE` 时,可返回标准输入的句柄。
156、哪个Win32函数可以从键盘读取一串文本并将其放入缓冲区?
ReadConsole
157、描述COORD结构。
COORD结构定义于Windows API中,用于标识屏幕的X和Y坐标。该结构包含两个字段:X和Y,均为WORD类型。字段X相对于结构起始位置的偏移量为0,字段Y的偏移量为2。其定义如下:
```text
COORD STRUCT
X WORD ? ; offset 00
Y WORD ? ; offset 02
COORD ENDS
158、哪个Win32函数可以更改控制台窗口的标题?
SetConsoleTitle函数可以更改控制台窗口的标题。
159、哪个Win32函数可以让你改变屏幕缓冲区的尺寸?
SetConsoleScreenBufferSize函数可以设置屏幕缓冲区的大小为X列Y行。
160、哪个Win32函数可以让你更改后续文本输出的颜色?
SetConsoleTextAttribute
函数可以更改后续文本输出到控制台窗口的前景色和背景色。
161、哪个Win32函数可以将属性值数组复制到控制台屏幕缓冲区的连续单元格中?
WriteConsoleOutputAttribute函数
162、哪个Win32函数可以让程序暂停指定的毫秒数?
Win32的Sleep函数可以让程序暂停指定的毫秒数。
163、列举两个调用 MessageBox 函数时可以使用的按钮常量。
MB_RETRYCANCEL、MB_ABORTRETRYIGNORE
164、列举两个调用MessageBox函数时可以使用的图标常量。
MB_ICONSTOP、MB_ICONQUESTION
165、列举WinMain(启动)过程执行的至少三项任务。
显示并更新主窗口;
开始一个接收和分发消息的循环,该循环持续到用户关闭应用程序窗口;
调用
GetMessage
从程序的消息队列中检索下一个可用消息;
若
GetMessage
检索到
WM_QUIT
消息则停止程序,对于其他消息,将其传递给
DispatchMessage
函数。
166、描述示例程序中WinProc过程的作用。
WinProc过程接收并处理与窗口相关的所有事件消息,大多数事件由用户通过鼠标点击、拖动和按键等操作发起。该过程的任务是解码每条消息,若消息被识别,则执行与该消息相关的面向应用程序的任务。对于未处理的消息,会传递给MS-Windows的默认消息处理程序`DefWindowProc`。
167、示例程序中WinProc过程处理哪些消息?
示例程序中
WinProc
过程处理以下三种消息:
WM_LBUTTONDOWN
(用户按下鼠标左键时生成)
WM_CREATE
(主窗口刚创建时)
WM_CLOSE
(应用程序主窗口即将关闭时)
168、描述示例程序中 ErrorHandler 过程的作用。
ErrorHandler 过程是可选的,当系统在程序主窗口的注册和创建过程中报告错误时会调用它。它有几个重要任务:
调用
GetLastError
检索系统错误号;
调用
FormatMessage
检索适当的系统格式化错误消息字符串;
调用
MessageBox
显示包含错误消息字符串的弹出消息框;
调用
LocalFree
释放错误消息字符串使用的内存。
169、调用CreateWindow后立即激活的消息框是在应用程序主窗口之前还是之后出现?
在调用
CreateWindowEx
创建主窗口后,若创建成功会保存窗口句柄、显示并绘制窗口,之后才调用
MessageBox
显示消息框,所以消息框在应用程序主窗口之后出现。
170、在段的相关概念中,什么是描述符?
段描述符可存在于
全局描述符表
和
局部描述符表
两种表中。除了段的基地址外,段描述符还包含指定段限制和段类型的位映射字段。段描述符还可以包含保护级别,保护操作系统数据不被应用程序访问。
描述符的各个选择器字段描述如下:
基地址
:是一个32位整数,定义了段在4GB线性地址空间中的起始位置;
特权级别
:可在0到3之间分配,0最具特权,通常用于操作系统内核代码;
段类型
:指示段的类型,指定对段的访问类型和段的增长方向;
段存在标志位
:指示段当前是否存在于物理内存中;
粒度标志位
:决定段限制字段的解释方式;
段限制
:是一个20位整数,指定段的大小,根据粒度标志位以字节或4096字节为单位解释。
171、一个系统有多少个局部描述符表(LDT)和全局描述符表(GDT)?
一个系统只有一个全局描述符表(GDT);在多任务操作系统中,每个任务或程序通常被分配一个局部描述符表(LDT),因此系统中LDT的数量取决于任务或程序的数量。
172、多任务处理在Windows环境中可行,但在DOS中不可行。
这句话是正确的。Windows是多任务操作系统,支持同时运行多个程序;而DOS是单任务操作系统,一次通常只能运行一个程序。
173、给出一个调用ReadConsole函数的示例。
以下是调用
ReadConsole
函数的示例代码:
; Read From the Console (ReadConsole.asm)
INCLUDE Irvine32.inc
BufSize = 80
.data
buffer BYTE BufSize DUP(?),0,0
stdInHandle HANDLE ?
bytesRead DWORD ?
.code
main PROC
; Get handle to standard input
INVOKE GetStdHandle, STD_INPUT_HANDLE
mov stdInHandle,eax
; Wait for user input
INVOKE ReadConsole, stdInHandle, ADDR buffer, BufSize, ADDR bytesRead, 0
; Display the buffer
mov esi,OFFSET buffer
mov ecx,bytesRead
mov ebx,TYPE buffer
call DumpMem
exit
main ENDP
END main
174、展示一个对WriteConsole函数的调用示例。
INVOKE WriteConsole, consoleHandle, ADDR message, messageSize, ADDR bytesWritten, 0
175、给出一个调用CreateFile函数的示例,该示例能打开同名的现有文件,若文件不存在则创建一个具有普通属性的新文件。
INVOKE CreateFile, ADDR filename, GENERIC_WRITE, DO_NOT_SHARE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0
176、展示一个如何在汇编语言程序中使用动态内存分配调用来分配堆内存的示例。
以下是一个使用动态内存分配创建并填充一个1000字节数组的示例程序(Heaptest1.asm):
; Heap Test #1 (Heaptest1.asm)
INCLUDE Irvine32.inc
; This program uses dynamic memory allocation to allocate and
; fill an array of bytes.
.data
ARRAY_SIZE = 1000
FILL_VAL EQU 0FFh
hHeap HANDLE ? ; handle to the process heap
pArray DWORD ? ; pointer to block of memory
newHeap DWORD ? ; handle to new heap
str1 BYTE "Heap size is: ",0
.code
main PROC
INVOKE GetProcessHeap ; get handle prog's heap
.IF eax == NULL ; if failed, display message
call WriteWindowsMsg
jmp quit
.ELSE
mov hHeap,eax ; success
.ENDIF
call allocate_array
jnc arrayOk ; failed (CF = 1)?
call WriteWindowsMsg
call Crlf
jmp quit
arrayOk: ; ok to fill the array
call fill_array
call display_array
call Crlf
; free the array
INVOKE HeapFree, hHeap, 0, pArray
quit:
exit
main ENDP
;--------------------------------------------------------
allocate_array PROC USES eax
;
; Dynamically allocates space for the array.
; Receives: EAX = handle to the program heap
; Returns: CF = 0 if the memory allocation succeeds.
;--------------------------------------------------------
INVOKE HeapAlloc, hHeap, HEAP_ZERO_MEMORY, ARRAY_SIZE
177、给出一个调用 MessageBox 函数的示例。
以下是一个调用 MessageBox 函数的示例,完整的 MessageBox 函数原型为:
MessageBoxA PROTO, hWnd:DWORD, lpText:PTR BYTE, lpCaption:PTR BYTE, uType:DWORD
在控制台应用程序中可将
hWnd
设为
NULL
,
lpText
是指向要显示在消息框内的以空字符结尾的字符串的指针,
lpCaption
指向对话框标题的以空字符结尾的字符串,
uType
指定对话框的内容和行为。
代码示例如下:
INVOKE MessageBox, NULL, ADDR warningMsg,