反转和更改给定字符串 x86 程序集的大小写

Reversing and changing case of a given string x86 assembly

这个程序的objective是在转换每个字母的大小写的同时反转给定的字符串。字符串不能超过 20 个字符,如果输入超过 20 个字符,程序会要求用户重新输入字符串。当用户输入 'enter' 并打印结束句后程序结束。

实现这个我有 3 个问题:

  1. 我尝试使用调用 ReadString 获取输入字符串,并且由于此过程在给出回车键时停止,所以当我按回车键正常完成程序时,控制台冻结结束。我如何更正我的代码以使其打印结束消息,然后使用 return 值 0 正常结束程序?

  2. 如果输入的字符串超过20个字符,需要用户重新输入。所以我写了ja L1。 Bur 由于某种原因,mov bytecount,eax; cmp字节数,20;似乎无法正确过滤案例。当执行到mov bytecount,eax这行时,bytecount的值是正确的,但是当程序执行到下一行cmp bytecount,20时,bytecount的值就变了。我不知道我做错了什么。

  3. CaseChange过程在执行的时候死机了,所以我猜它是无限循环的,但是我找不到错误的条件。

.data
MaxLength = 20
prompt3 BYTE "End of program",0
buffer BYTE MaxLength DUP(0)
bytecount DWORD ?

.code 
main PROC
    call Clrscr
L1: mov edx, OFFSET buffer
    mov ecx, SIZEOF buffer
    call PromptForInput     ; printing input prompt
    call ReadString      
    mov bytecount, eax
    cmp bytecount, 20       ;*** get input again if number of characters in the string is greater than 20
    ja L1                   ;*** 
    call ReverseString     
    call CaseChange         ;***
    mov edx, OFFSET buffer
    call WriteString        ;printing the result
    loop L1
    mov edx, OFFSET prompt3 ;*** after input <ent> how do I print prompt3?
    call WriteString
    exit
main ENDP

CaseChange PROC
    pushad 
    mov eax, OFFSET buffer
L1:
    mov dl, BYTE PTR[eax]
    test dl, dl
    jz L3
    cmp dl, 'A'
    jl L3
    xor dl,32
    cmp dl,'z'
L2:
    inc eax
    jmp L1
L3:
    popad
    ret
CaseChange ENDP

(输入提示):猫和狗。

(输出提示):.SGOd DNA STAc

(输入提示):对于给定的限制来说太长了

(输入提示):

节目结束

手册告诉我们 ReadString:

Reads a string of up to ECX non-null characters from standard input, stopping when the user presses the Enter key.
A null byte is stored following the characters input, but the trailing carriage return and line feed characters are not placed into the buffer.
ECX should always be smaller than the buffer size (never equal to the buffer size) because the null byte could be the (ECX+1)th character stored.

接下来可以清楚地看到您需要扩大缓冲区:

buffer BYTE MaxLength + 1 DUP (0)

如果您指定了 ECX=MaxLength,那么您无法获得超过 MaxLength 个字符的输入,因此没有真正需要测试这种情况。 (*)

如果用户按下没有前导字符的 enter 键,则 ReadString 将 return 与 EAX=0.对此进行测试并跳转到您的最后一条消息。

一个大错误是你写loop L1的地方。 loop 指令与 ECX 寄存器一起执行已知次数的迭代。您的程序需要不附加任何条件地跳回到顶部。使用 jmp L1.

如果你把事情放在一起是最好的。不要将 call PromptForInputcall ReadString 及其参数混用。你能确定 PromptForInput 不会改变 EDXECX 吗?

L1: call    PromptForInput

    mov     edx, OFFSET buffer
    mov     ecx, MaxLength
    call    ReadString         ; -> EAX
    test    eax, eax
    jz      L2                 ; Exit

    call    ReverseString       ; Is this working fine?
    call    CaseChange

    mov     edx, OFFSET buffer
    call    WriteString         ; Printing the result

    jmp     L1

L2:
    mov     edx, OFFSET prompt3
    call    WriteString         ; Final message

    exit

  • cmp dl, 'A' jl L3 ChangeCase过程需要遍历整个字符串,但是一遇到小于65的字节就走,请使用unsigned条件使用 ASCII 码 [0,255] 时。

  • xor dl,32 您实际上并没有在字符串内存中写入任何更改。

  • cmp dl,'z' 你不对这个比较采取行动。

如果您只需要保留 1 个寄存器,则不要使用 pushadpopad

CaseChange PROC
    push    esi
    mov     esi, OFFSET buffer
L1:
    lodsb
    test    al, al        ; End of string ?
    jz      L2
    or      al, 32        ; If "A".."Z" Then "a".."z"
    cmp     al, 'a'
    jb      L1
    cmp     al, 'z'
    ja      L1
    xor     byte ptr [esi-1], 32  ; Change case IN string memory
    jmp     L1
L2:
    pop     esi
    ret
CaseChange ENDP

(*) 如果你想强加这个 "String cannot be longer than 20 characters" 错误然后定义一个更大的缓冲区并允许 ReadString 到 return 超过 20 个字符所以您可以在程序中跳回:

buffer BYTE 99 + 1 DUP (0)

...

L1: call    PromptForInput

    mov     edx, OFFSET buffer
    mov     ecx, 99
    call    ReadString         ; -> EAX
    cmp     eax, 20
    ja      L1
    test    eax, eax
    jz      L2                 ; Exit

最后一个建议是通过独立测试确保 ReverseStringCaseChange 正常:

    call    ReverseString
    ;;;call    CaseChange
    mov     edx, OFFSET buffer
    call    WriteString         ; Printing the result

以后

    ;;;call    ReverseString
    call    CaseChange
    mov     edx, OFFSET buffer
    call    WriteString         ; Printing the result

只有那时

    call    ReverseString
    call    CaseChange
    mov     edx, OFFSET buffer
    call    WriteString         ; Printing the result