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

时间:2019-05-05 14:25:26

标签: string assembly input x86 irvine32

该程序的目的是在切换每个字母的大小写的同时反转给定的字符串。字符串不能超过20个字符,如果输入长度超过20个字符,则程序要求用户再次输入字符串。程序在用户输入“ enter”时结束,并且在打印结束语句后结束。

为此,我有3个问题:

  1. 我试图通过调用ReadString来获取输入字符串,并且由于在输入Enter键后此过程停止,因此当我按Enter键正常完成程序时,控制台冻结结束。如何纠正我的代码以使其显示结束消息,然后正常地以返回值0结束程序?

  2. 如果输入字符串长于20个字符,则应要求用户再次输入字符串。所以我写了ja L1。 Bur由于某种原因,mov字节数,eax; cmp bytecount,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

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

(输入提示):

程序结束

1 个答案:

答案 0 :(得分:1)

该手册告诉我们 ReadString

  

从标准输入中读取最多包含ECX个非空字符串,当用户按下Enter键时停止。
  在输入的字符之后会存储一个空字节,但是尾随回车符和换行符不会放入缓冲区。
   ECX应该始终小于缓冲区大小(绝不等于缓冲区大小),因为空字节可能是存储的第(ECX + 1)个字符。

在此之后,很明显,您需要扩大缓冲区:

buffer BYTE MaxLength + 1 DUP (0)

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

如果用户按 enter 键且没有前面的字符,则 ReadString 将返回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

(*)如果要强加此“字符串不能超过20个字符”错误,则定义一个更大的缓冲区,并允许 ReadString 返回超过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

最后的建议是通过独立测试 ReverseString CaseChange 正常:

    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