比较汇编语言中的字符串时出错:0xC0000005:访问冲突读取位置 0x00000043

Error comparing strings in assembly language: 0xC0000005: Access violation reading location 0x00000043

该代码应该将输入的字符串与各种硬编码选项进行比较以提供菜单。

这是我正在使用的代码

.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:

Exception thrown at 0x00F6195F in Application.exe: 0xC0000005: Access violation reading location 0x00000043.

问题是您将源寄存器和目标寄存器都设置为错误的值。
我要解释一下:

函数 ReadConsole 具有以下签名:

BOOL WINAPI ReadConsole(
  _In_     HANDLE  hConsoleInput,
  _Out_    LPVOID  lpBuffer,
  _In_     DWORD   nNumberOfCharsToRead,
  _Out_    LPDWORD lpNumberOfCharsRead,
  _In_opt_ LPVOID  pInputControl
);

mov ESI, choice

您正在将 ReadConsolechoice 的第四个参数复制到 ESI
choice 包含 NumberOfCharsRead,因此它不是内存指针,而是一个 长度值 。这行不通。

mov EDI, letterC

您将 letterC 的值 移动到 EDI 而不是其地址。要获取 EDI 的地址,您必须使用

mov EDI, OFFSET letterC

此错误在您的错误消息中变得很明显

Access violation reading location 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 SCASBAL (MOV AL, letterC) 中的字符 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