更改信件案例(汇编x86)

时间:2017-03-16 22:47:25

标签: assembly x86

我是装配工的新手,正在我的实验室工作,进行装配课程。对于实验的这一部分,我需要将字符串转换为相反的大小写。例如:

如果给出了字符串

  

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
  }
}

1 个答案:

答案 0 :(得分:5)

您的代码中的问题在于您将aleax用于两个不同的目的。
aleax的一部分。因此,如果您更改al,实际上您正在更改eax的最低有效字节 因为您使用eax作为基本指针,所以不应该操作它,而是使用像edx这样的免费寄存器及其最低字节dl来执行大写操作。
如果您操作al,则指针eax将指向整个地方,从而导致不需要的结果。

深入研究代码,不需要同时使用ecxeax作为指针,其中一个就足够了,因为你可以通过阅读告诉你在字符串的末尾它终止零字节。

您可以轻松优化此代码:

__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中,ecxedx在大多数平台上被视为 volatile ,而其他一些寄存器可能不会。因此,如果你可以逃脱它,最好只使用那些寄存器 如果您使用其他寄存器,则必须push,然后在例程开始时,pop在例程退出之前。