C++ 汇编:循环一系列字符并交换它们

C++ 汇编:循环一系列字符并交换它们,c++,loops,assembly,reverse,masm,C++,Loops,Assembly,Reverse,Masm,我的任务是在汇编中实现一个函数,该函数将执行以下操作: 循环遍历一系列字符并交换它们,以使最终结果为反向的原始字符串(100点) 提示:从用户处收集字符串作为C字符串,然后将其与用户输入的字符数一起传递给汇编函数。要找出字符数,请使用strlen()函数 我已经编写了C++和汇编程序,它的工作范围很好:例如,如果我输入12345,输出正确地显示为54321,但是如果超过5个字符:输出开始错误:例如,如果我输入123456,输出是:653241。如果有人能指出我的错误,我将不胜感激: .code

我的任务是在汇编中实现一个函数,该函数将执行以下操作: 循环遍历一系列字符并交换它们,以使最终结果为反向的原始字符串(100点) 提示:从用户处收集字符串作为C字符串,然后将其与用户输入的字符数一起传递给汇编函数。要找出字符数,请使用strlen()函数

我已经编写了C++和汇编程序,它的工作范围很好:例如,如果我输入12345,输出正确地显示为54321,但是如果超过5个字符:输出开始错误:例如,如果我输入123456,输出是:653241。如果有人能指出我的错误,我将不胜感激:

.code

_reverse PROC 
  push ebp     
  mov ebp,esp  ;stack pointer to ebp

  mov ebx,[ebp+8]       ; address of first array element
  mov ecx,[ebp+12]  ; the number of elemets in array
  mov eax,ebx   
  mov ebp,0         ;move 0 to base pointer 
  mov edx,0     ; set data register to 0
  mov edi,0

Setup:

  mov esi , ecx
  shr ecx,1
  add ecx,edx
  dec esi

reverse:

  cmp ebp , ecx
  je allDone

  mov edx, eax
  add eax , edi
  add edx , esi

Swap:
  mov bl, [edx]
  mov bh, [eax]

  mov [edx],bh
  mov [eax],bl

  inc edi
  dec esi

  cmp edi, esi
  je allDone

  inc ebp
  jmp reverse

allDone:
  pop ebp               ; pop ebp out of stack
  ret                   ; retunr the value of eax
 _reverse ENDP

END

这里是我的C++代码:

#include<iostream>
#include <string>

using namespace std;
extern"C"
char reverse(char*, int);

int main()
{
  char str[64] = {NULL};
  int lenght;

  cout << " Please Enter the text you want to reverse:";
  cin >> str;
  lenght = strlen(str);

  reverse(str, lenght);

  cout << " the reversed of the input is: " << str << endl;

  }
#包括
#包括
使用名称空间std;
外部“C”
字符反转(字符*,整数);
int main()
{
char str[64]={NULL};
内部长度;
cout>str;
长度=strlen(str);
反向(str,lenght);

无法您没有对代码进行注释,因此请确定您正试图执行的操作,但看起来您正在使用MOV/ADD手动执行数组索引,而不是使用类似
[eax+edi]
的寻址模式

但是,看起来您正在修改原始值,然后以一种在未修改的情况下有意义的方式使用它

  mov edx, eax         ; EAX holds a pointer to the start of array, read every iter
  add eax , edi        ; modify the start of the array!!!
  add edx , esi

Swap:
  inc edi
  dec esi
EAX每一步都会随着EDI的增加而线性增加,所以EAX会以几何方式增加(积分(x*dx)=x^2)

在调试器中单步执行此操作应该很容易找到



顺便说一句,通常的方法是向上走一个指针,向下走一个指针,当它们交叉时从循环中掉出来。然后你不需要一个单独的计数器,只需要
cmp/ja
(不要检查JNE或JE,因为它们可以相互交叉而不相等。)

总的来说,从字符串的两端开始,交换元素,直到到达中间,这是一个正确的想法。不过,实现是可怕的

mov ebp,0         ;move 0 to base pointer
这似乎是循环计数器(注释是无用的,甚至更糟);我想我的想法是交换
length/2
元素,这很好。提示我只需比较指针/索引,一旦它们发生冲突就退出

mov edx,0     ; set data register to 0
...
add ecx,edx
mov edx, eax
无用的和误导性的

mov edi,0
mov esi , ecx
dec esi
看起来像是指向字符串开始/结束的索引。好的。提示我应该使用指向字符串开始/结束的指针;但索引也可以工作

cmp ebp , ecx
je allDone
如果执行了长度/2次迭代,则退出。确定

mov edx, eax
add eax , edi
add edx , esi
eax
edx
指向要交换的当前符号。几乎可以,但这会破坏eax!第二次之后的每个循环迭代都会使用错误的指针!这就是问题的根源。如果使用指针而不是索引,或者使用偏移寻址
[eax+edi]
/
[eax+esi]

...
交换部分可以

cmp edi, esi
je allDone

第二个退出条件,这一次比较索引冲突!通常一个退出条件就足够了;几个退出条件通常是多余的,或者暗示了算法中的某些缺陷。同样,相等比较是不够的-索引可以在单次迭代中从
ediesi

没有注意到任何实际错误t、 非常奇怪的东西。如果你打算把EBP用作通用寄存器,你应该省去
mov EBP,esp
的东西。(并且只需访问带有esp偏移量的args)。像
将数据寄存器设置为0
这样的注释是无用的。有用的是描述您的函数使用EDX的目的。
mov eax,ebx
在函数顶部似乎是无用的,为什么不首先加载到eax中呢?您在函数其余部分中唯一使用的ebx是将字节放入BL和BH中。一个bug是您应该像保存/恢复EBP一样保存/恢复EBX,因为它在所有常见的32位调用约定中都是保留调用的。您可能在某个地方有另一个错误,因为踩下调用方的EBX值可能不会导致您看到的行为。您应该在调试器中单步查看代码,以了解它的作用。谢谢非常感谢Cordes先生的精彩和建设性的评论我很抱歉我上传了一个如此糟糕的代码,没有任何评论,我对我的代码感到非常失望,我忘记了看我愚蠢的评论。代码的第一部分是我们的指导老师给我们的,所以我甚至没有看里面发生了什么,我替换了EBX正如你告诉我的那样使用EAX,它工作得很好。修复了注释。保存并恢复了EBX。自从我上大学第二学期以来,我从来没有听说过任何关于单步调试的事情。我这样做了,并找出了错误所在。我按照你告诉我的使用了寻址模式,并以几何方式修复了EAX的增量。还使用了compa的指针戒指而不是索引,因为我不知道它们可以相互交叉,甚至不相等,所以我按照你的建议使用了JA,它起了作用perfectly@ArashDe:很高兴有帮助。如果您觉得此答案回答了问题,您应该单击投票箭头下的复选框,将此答案标记为已接受。