我是装配工的新手,正在我的实验室工作,进行装配课程。对于实验的这一部分,我需要将字符串转换为相反的大小写。例如:
如果给出了字符串
TheDonald
它应该返回
tHEdONALD
可能有句号或其他特殊字符,在这种情况下我会留下它们。我也不允许使用32位寄存器。我应该只使用8位版本的x86通用寄存器。
到目前为止,我有这个:
void changeCase(char *string)
{
__asm
{
// BEGIN YOUR CODE HERE
mov eax, string; // move the string into eax
mov ecx, 0; // ecx will be counter
BEGIN_LOOP:
cmp byte ptr[eax + ecx * 1], 0;
je END;
mov al, byte ptr[eax + ecx * 1]; // get the value of the current counter
cmp al, 65; // compare first char with A
jl NEXT_INDEX;
cmp al, 91;
jl UPPER_CASE;
cmp al, 97;
jl NEXT_INDEX;
cmp al, 123;
jl LOWER_CASE;
jmp NEXT_INDEX;
UPPER_CASE: // if upper case, make it lower case then go to next index
add al, 32;
mov byte ptr[eax + ecx * 1], al;
jmp NEXT_INDEX;
LOWER_CASE: // if lower case, make it upper case then go to next index
sub al, 32;
mov byte ptr[eax + ecx * 1], al;
jmp NEXT_INDEX;
NEXT_INDEX:
inc ecx;
jmp BEGIN_LOOP;
END:
// END YOUR CODE HERE
}
}
答案 0 :(得分:5)
您的代码中的问题在于您将al
和eax
用于两个不同的目的。
al
是eax
的一部分。因此,如果您更改al
,实际上您正在更改eax
的最低有效字节
因为您使用eax
作为基本指针,所以不应该操作它,而是使用像edx
这样的免费寄存器及其最低字节dl
来执行大写操作。
如果您操作al
,则指针eax
将指向整个地方,从而导致不需要的结果。
深入研究代码,不需要同时使用ecx
和eax
作为指针,其中一个就足够了,因为你可以通过阅读告诉你在字符串的末尾它终止零字节。
您可以轻松优化此代码:
__asm{
// BEGIN YOUR CODE HERE
mov eax, string; // move the string into eax
BEGIN_LOOP:
mov dl, byte ptr[eax]; //get the current char.
test dl,dl //is it the terminating zero?
jz END //yes, we're done
cmp dl, 'A'; // compare first char with A
jl NEXT_INDEX; //smaller than A, skip
cmp dl, 'z'; //compare char with z
jg NEXT_INDEX; //bigger than z, skip
xor dl,32 //'a' = 'A' + 32 and 'A' = 'a' - 32 use xor to filp that bit
cmp dl,'z' //Make sure we don't flip '[]\^_'
cmovle [eax],dl //only write when result within bounds
NEXT_INDEX: //write back the flipped char.
inc eax; //next char.
jmp BEGIN_LOOP;
END:
}
有很多方法可以进一步优化它,但我不想过分复杂化这个问题
请注意,在x86_32编程eax
中,ecx
和edx
在大多数平台上被视为 volatile ,而其他一些寄存器可能不会。因此,如果你可以逃脱它,最好只使用那些寄存器
如果您使用其他寄存器,则必须push
,然后在例程开始时,pop
在例程退出之前。