代码应该将输入的字符串与各种硬编码选项进行比较以提供菜单。
这是我正在使用的代码
.stack 4096
...
GetStdHandle proto :dword
ReadConsoleA proto :dword, :dword, :dword, :dword, :dword
WriteConsoleA proto :dword, :dword, :dword, :dword, :dword
STD_INPUT_HANDLE equ -10
...
.data
...
bufSize = 80
inputHandle DWORD ?
buffer db bufSize dup(?)
choice DWORD ?
letterC DWORD "C"
...
.code
...
invoke GetStdHandle, STD_INPUT_HANDLE
mov inputHandle, eax
invoke ReadConsoleA, inputHandle, addr buffer, bufSize, addr choice,0
mov ESI, choice
mov EDI, letterC
CLD
MOV ECX,10
REPE CMPSB
...
它总是在最后一行给我一个错误REPE CMPSB
:
在应用程序.exe中0x00F6195F引发异常: 0xC0000005:访问冲突读取位置0x00000043。
问题是您将源寄存器和目标寄存器都设置为错误的值。
我将解释一下:
函数ReadConsole
具有以下签名:
BOOL WINAPI ReadConsole(
_In_ HANDLE hConsoleInput,
_Out_ LPVOID lpBuffer,
_In_ DWORD nNumberOfCharsToRead,
_Out_ LPDWORD lpNumberOfCharsRead,
_In_opt_ LPVOID pInputControl
);
跟
mov ESI, choice
您正在将ReadConsole
的第四个参数choice
复制到ESI
。choice
包含NumberOfCharsRead
,所以它不是内存指针,而是一个长度值。这行不通。
跟
mov EDI, letterC
将letterC
的值移动到EDI
而不是其地址。要获得EDI
地址,您必须使用
mov EDI, OFFSET letterC
此错误在您的错误消息中变得明显,该错误消息显示
访问违规读取位置0x00000043。
0x00000043
的值等于字符C
的 ASCII 字符值,0x43。要获取其地址 - 这将是正确的 - 您可以使用LEA
指令,如lea EDI, letterC
或更有效的OFFSET
指令。读取或写入值作为地址几乎总是会导致错误。
要使其正确,请考虑以下方法:
invoke ReadConsoleA, inputHandle, addr buffer, bufSize, addr choice,0
CLD
MOV ESI, OFFSET buffer ; address of buffer is source
MOV EDI, OFFSET letterC ; address of letterC is destination
MOV ECX, choice ; length of string is choice (bytes read)
REPE CMPSB ; execute
此解决方案更好,但它包含一个主要错误:REPE CMPSB
比较字符并继续比较它们,只要它们相等。但是您的letterC
只有一个字符长,因此在传递C
字符 - 第二次迭代后,您将获得溢出。
你的问题不清楚你真正期望什么,所以以下只是一个猜测:
一个可能的替代方案是使用REPNE SCASB
与字符letterC
在AL
(MOV AL, letterC
)中搜索C
的第一次出现:
invoke ReadConsoleA, inputHandle, addr buffer, bufSize, addr choice,0
CLD
MOV EDI, OFFSET buffer ; address of buffer is search source
MOV EAX, letterC ; value of letterC
MOV ECX, choice ; length of string is choice (bytes read)
REPNE SCASB ; execute