Winapi 为什么如果我输入的数字变高,它会返回错误的数字

Winapi 为什么如果我输入的数字变高,它会返回错误的数字,winapi,assembly,x86,masm,Winapi,Assembly,X86,Masm,我有以下代码,但我不明白为什么如果我输入的数字太高,它会返回错误的数字。这可能是因为数据类型以及除法和乘法,但我不知道确切的原因。如果你知道为什么我会感谢你的帮助 .586 .model flat, stdcall option casemap :none .stack 4096 extrn ExitProcess@4: proc GetStdHandle proto :dword ReadConsoleA proto :dword, :dword, :dword, :dword, :dwo

我有以下代码,但我不明白为什么如果我输入的数字太高,它会返回错误的数字。这可能是因为数据类型以及除法和乘法,但我不知道确切的原因。如果你知道为什么我会感谢你的帮助

.586
.model flat, stdcall
option casemap :none
.stack 4096
extrn ExitProcess@4: proc

GetStdHandle proto :dword
ReadConsoleA  proto :dword, :dword, :dword, :dword, :dword
WriteConsoleA proto :dword, :dword, :dword, :dword, :dword
STD_INPUT_HANDLE equ -10
STD_OUTPUT_HANDLE equ -11

.data

    bufSize = 80
    inputHandle DWORD ?
    buffer db bufSize dup(?)
    bytes_read  DWORD  ?
    sum_string db "The number was ",0
    outputHandle DWORD ?
    bytes_written dd ?
    actualNumber dw 0
    asciiBuf db 4 dup (0)
.code
  main:

    invoke GetStdHandle, STD_INPUT_HANDLE
    mov inputHandle, eax
    invoke ReadConsoleA, inputHandle, addr buffer, bufSize, addr bytes_read,0
    sub bytes_read, 2   ; -2 to remove cr,lf
    mov ebx,0

    mov al, byte ptr buffer+[ebx] 
    sub al,30h
    add [actualNumber],ax
getNext:
    inc bx
    cmp ebx,bytes_read
    jz cont
    mov ax,10
    mul [actualNumber]
    mov actualNumber,ax
    mov al, byte ptr buffer+[ebx] 
    sub al,30h
    add actualNumber,ax

    jmp getNext
cont:


    invoke GetStdHandle, STD_OUTPUT_HANDLE
    mov outputHandle, eax
    mov eax,LENGTHOF sum_string ;length of sum_string
    invoke WriteConsoleA, outputHandle, addr sum_string, eax, addr bytes_written, 0
    mov ax,[actualNumber]
    mov cl,10
    mov bl,3
nextNum:
    xor edx, edx
    div cl
    add ah,30h
    mov byte ptr asciiBuf+[ebx],ah
    dec ebx
    mov ah,0
    cmp al,0
    ja nextNum

    mov eax,4

    invoke WriteConsoleA, outputHandle, addr asciiBuf, eax, addr bytes_written, 0

    mov eax,0
    mov eax,bytes_written
    push    0

    call    ExitProcess@4
end     main

是的,您的返回值被一个最大值限制是合理的。此最大值为255的
字节
边界或65536的
单词
边界。让我逐一解释原因:

mov inputHandle, eax
invoke ReadConsoleA, inputHandle, addr buffer, bufSize, addr bytes_read,0
sub bytes_read, 2   ; -2 to remove cr,lf
mov ebx,0

mov al, byte ptr buffer+[ebx] 
sub al,30h
add [actualNumber],ax
在本部分中,您将调用
Win32 API
函数,该函数始终返回寄存器
EAX
中的
return
值。返回后,将32位返回值中较低的8位分配给
字节ptr buffer+[ebx]
,从中减去
30h
。然后通过
添加[actualNumber],AX
将刚刚在
AL
中修改的8位和
AH
中保留的返回值作为块
AX
添加到
WORD
变量。因此,
AH
源于
EAX
返回值,相当于
未定义的
。如果它是
0
,您可能会很幸运,但这不应该被假设

下一个问题是以下子程序:

getNext:
  inc bx
  cmp ebx,bytes_read
  jz cont
  mov ax,10
  mul [actualNumber]
  mov actualNumber,ax
  mov al, byte ptr buffer+[ebx] 
  sub al,30h
  add actualNumber,ax
  jmp getNext
您正在将十进制基数
10
移动到
WORD
寄存器
AX
并将其乘以
WORD
变量
[actualNumber]
。到目前为止,一切顺利。但是16位*16位
MUL
的结果返回到寄存器对
AX:DX
(低:高)。因此,您的
mov实际数ax
mov
s变量的低16位(
DX
被忽略,将结果限制为
result%65536
)。所以你的最大可能结果是MAX_WORD=65535。其他的一切只会给你AX中的模

mov al之后,字节ptr buffer+[ebx]
buffer[ebx]
指向的
byte
覆盖此结果的下8位,然后从中减去
30h
。记住:结果的高8位仍然保留在AH中,AX的高8位

然后使用
add actualNumber,ax
将该值(重新)添加到变量
actualNumber
。让我浓缩最后两段:

Operation                        |        AX        |
                                 |  AL          AH  |
mov actualNumber,ax              | ................ |
mov al, byte ptr buffer+[ebx]    | ........     AH  |
sub al,30h                       | ....-30h     AH  |
add actualNumber,ax              | ................ |
因此,您正在通过
AL
修改
AX
的低8位,然后将
actualNumber
/
AH
的高8位添加到自身中-有效地将
AH
加倍,然后将其添加到
actualNumber
,如下所示:

actualNumber = 256 * (2 * AH) + (byte ptr buffer[ebx]-30h)      ; I doubt you want that ;-)

这些问题可能会导致与预期结果的几处偏差。

是的,您的返回值被最大值限制是合理的。此最大值为255的
字节
边界或65536的
单词
边界。让我逐一解释原因:

mov inputHandle, eax
invoke ReadConsoleA, inputHandle, addr buffer, bufSize, addr bytes_read,0
sub bytes_read, 2   ; -2 to remove cr,lf
mov ebx,0

mov al, byte ptr buffer+[ebx] 
sub al,30h
add [actualNumber],ax
在本部分中,您将调用
Win32 API
函数,该函数始终返回寄存器
EAX
中的
return
值。返回后,将32位返回值中较低的8位分配给
字节ptr buffer+[ebx]
,从中减去
30h
。然后通过
添加[actualNumber],AX
将刚刚在
AL
中修改的8位和
AH
中保留的返回值作为块
AX
添加到
WORD
变量。因此,
AH
源于
EAX
返回值,相当于
未定义的
。如果它是
0
,您可能会很幸运,但这不应该被假设

下一个问题是以下子程序:

getNext:
  inc bx
  cmp ebx,bytes_read
  jz cont
  mov ax,10
  mul [actualNumber]
  mov actualNumber,ax
  mov al, byte ptr buffer+[ebx] 
  sub al,30h
  add actualNumber,ax
  jmp getNext
您正在将十进制基数
10
移动到
WORD
寄存器
AX
并将其乘以
WORD
变量
[actualNumber]
。到目前为止,一切顺利。但是16位*16位
MUL
的结果返回到寄存器对
AX:DX
(低:高)。因此,您的
mov实际数ax
mov
s变量的低16位(
DX
被忽略,将结果限制为
result%65536
)。所以你的最大可能结果是MAX_WORD=65535。其他的一切只会给你AX中的模

mov al之后,字节ptr buffer+[ebx]
buffer[ebx]
指向的
byte
覆盖此结果的下8位,然后从中减去
30h
。记住:结果的高8位仍然保留在AH中,AX的高8位

然后使用
add actualNumber,ax
将该值(重新)添加到变量
actualNumber
。让我浓缩最后两段:

Operation                        |        AX        |
                                 |  AL          AH  |
mov actualNumber,ax              | ................ |
mov al, byte ptr buffer+[ebx]    | ........     AH  |
sub al,30h                       | ....-30h     AH  |
add actualNumber,ax              | ................ |
因此,您正在通过
AL
修改
AX
的低8位,然后将
actualNumber
/
AH
的高8位添加到自身中-有效地将
AH
加倍,然后将其添加到
actualNumber
,如下所示:

actualNumber = 256 * (2 * AH) + (byte ptr buffer[ebx]-30h)      ; I doubt you want that ;-)

这些问题可能会导致与预期结果的一些偏差。

Microsoft在其Visual Studio环境中有一个很好的调试器。也可以。当你说“太高”和“错误的数字”时,你并没有给我们提供太多的信息。我猜你正在尝试使用一个比你设计的代码要处理的大小更大的数字。Microsoft在其Visual Studio环境中有一个很好的调试器。也可以。当你说“太高”和“错误的数字”时,你并没有给我们太多的信息。作为猜测,我会想象你正在尝试使用一个比你设计的代码要处理的大小更大的数字。谢谢你的帮助,但我不明白实际数字=256*(2*AH)+(字节ptr缓冲区[ebx]-30h)@傻瓜亚当:很简单:
AX
是(256*AH)+AL。或者用另一种符号: