我想调用一个函数,该函数将大写到小写转换为用户键入的字符串,并保留特殊字符。此部分有效,但仅对于前4个字符,此后的所有内容都会被截断。我相信这是因为我已将参数定义为DWORD:
我尝试使用PAGE
,PARA
和BYTE
。前两个不起作用,带字节的类型为missmatch。
upperToLower proc, source:dword, auxtarget:dword
mov eax, source ;Point to string
mov ebx, auxtarget ; point to destination
L1:
mov dl, [eax] ; Get a character from buffer
cmp byte ptr [eax], 0 ; End of string? (not counters)
je printString ; if true, jump to printString
cmp dl, 65 ; 65 == 'A'
jl notUpper ; if less, it's not uppercase
cmp dl, 90 ; 90 == 'Z'
jg notUpper ; if greater, it's not uppercase
xor dl, 100000b ; XOR to change upper to lower
mov [ebx], dl ; add char to target
inc eax ; Move counter up
inc ebx ; move counter up
jmp L1 ; loop
notUpper: ; not uppercase
mov [ebx], dl ; copy the letter
inc eax ;next letter
inc ebx
jmp L1
printString:
invoke WriteConsoleA, consoleOutHandle, auxtarget, sizeof auxtarget, bytesWritten, 0
ret
upperToLower endp
协议:
upperToLower PROTO,
source: dword,
auxtarget: dword
调用:
invoke upperToLower, offset buffer, offset target
buffer参数为:buffer db 128 DUP(?)
如何打印整个字符串,而不仅仅是前4个字符?
答案 0 :(得分:2)
为什么只打印4个字符?您使用以下命令将字符串写入控制台:
invoke WriteConsoleA, consoleOutHandle, auxtarget, sizeof auxtarget, bytesWritten, 0
sizeof auxtarget
参数是auxtarget
的大小,它是DWORD
(4个字节),因此您只要求打印4个字节。您需要传递字符串的长度。您可以通过在 EAX 中获取结束地址并从中减去source
指针来轻松地做到这一点。结果将是您遍历的字符串的长度。
将代码修改为:
printString:
sub eax, source
invoke WriteConsoleA, consoleOutHandle, auxtarget, eax, bytesWritten, 0
遵循 C 调用约定的代码版本,同时使用源缓冲区和目标缓冲区,测试指针以确保它们不为NULL,并使用类似的{ {3}}如下:
upperToLower proc uses edi esi, source:dword, dest:dword
; uses ESI EDI is used to tell assembler we are clobbering two of
; the cdecl calling convetions non-volatile registers. See:
; https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl
mov esi, source ; ESI = Pointer to string
test esi, esi ; Is source a NULL pointer?
jz done ; If it is then we are done
mov edi, dest ; EDI = Pointer to string
test edi, edi ; Is dest a NULL pointer?
jz done ; If it is then we are done
xor edx, edx ; EDX = 0 = current character index into the strings
jmp getnextchar ; Jump into loop at point of getting next character
charloop:
lea ecx, [eax - 'A'] ; cl = al-'A', and we do not care about the rest
; of the register
cmp cl, 25 ; if(c >= 'A' && c <= 'Z') c += 0x20;
lea ecx, [eax + 20h] ; without affecting flags
cmovna eax, ecx ; take the +0x20 version if it was in the
; uppercase range to start with
mov [edi + edx], al ; Update character in destination string
inc edx ; Go to next character
getnextchar:
movzx eax, byte ptr [esi + edx]
; mov al, [esi + edx] leaving high garbage in EAX is ok
; too, but this avoids a partial-register stall
; when doing the mov+sub
; in one instruction with LEA
test eax, eax ; Is the character NUL(0) terminator?
jnz charloop ; If not go back and process character
printString:
; EDI = source, EDX = length of string
invoke WriteConsoleA, consoleOutHandle, edi, edx, bytesWritten, 0
mov edx, sizeof buffer
done:
ret
upperToLower endp
采用一个参数并将源字符串更改为大写的版本可以通过以下方式完成:
upperToLower proc, source:dword
mov edx, source ; EDX = Pointer to string
test edx, edx ; Is it a NULL pointer?
jz done ; If it is then we are done
jmp getnextchar ; Jump into loop at point of getting next character
charloop:
lea ecx, [eax - 'A'] ; cl = al-'A', and we do not care about the rest
; of the register
cmp cl, 25 ; if(c >= 'A' && c <= 'Z') c += 0x20;
lea ecx, [eax + 20h] ; without affecting flags
cmovna eax, ecx ; take the +0x20 version if it was in the
; uppercase range to start with
mov [edx], al ; Update character in string
inc edx ; Go to next character
getnextchar:
movzx eax, byte ptr [edx] ; mov al, [edx] leaving high garbage in EAX is ok, too,
; but this avoids a partial-register stall
; when doing the mov+sub in one instruction with LEA
test eax, eax ; Is the character NUL(0) terminator?
jnz charloop ; If not go back and process character
printString:
sub edx, source ; EDX-source=length
invoke WriteConsoleA, consoleOutHandle, source, edx, bytesWritten, 0
done:
ret
upperToLower endp
upperToLower
函数通常不会自行打印。通常,您会调用upperToLower
仅进行转换,然后在单独的调用中将字符串输出到显示器。