C++ 对组装中的循环有效

C++ 对组装中的循环有效,c++,visual-studio,visual-c++,assembly,for-loop,C++,Visual Studio,Visual C++,Assembly,For Loop,我目前正试图适应汇编程序,我在C++中编写了for循环,然后我在拆卸中查看了它。我想知道是否有人可以向我解释每一步的作用和/或如何手动改进循环 for (int i = 0; i < length; i++){ 013A17AE mov dword ptr [i],0 013A17B5 jmp encrypt_chars+30h (13A17C0h) 013A17B7 mov eax,dword p

我目前正试图适应汇编程序,我在C++中编写了for循环,然后我在拆卸中查看了它。我想知道是否有人可以向我解释每一步的作用和/或如何手动改进循环

for (int i = 0; i < length; i++){
     013A17AE  mov         dword ptr [i],0  
     013A17B5  jmp         encrypt_chars+30h (13A17C0h)  
     013A17B7  mov         eax,dword ptr [i]  
     013A17BA  add         eax,1  
     013A17BD  mov         dword ptr [i],eax  
     013A17C0  mov         eax,dword ptr [i]  
     013A17C3  cmp         eax,dword ptr [length]  
     013A17C6  jge         encrypt_chars+6Bh (13A17FBh)  
temp_char = OChars [i];         // get next char from original string
     013A17C8  mov         eax,dword ptr [i]  
     013A17CB  mov         cl,byte ptr OChars (13AB138h)[eax]  
     013A17D1  mov         byte ptr [temp_char],cl  
for(int i=0;i

提前感谢。

首先,我要注意,您发布的内容似乎只包含循环体的一部分。其次,它看起来像是在关闭所有优化的情况下编译的——当/如果打开优化,如果结果看起来很不一样,请不要感到惊讶

也就是说,让我们逐行查看代码:

 013A17AE mov dword ptr [i],0
这基本上就是
i=0

 013A17B5 jmp encrypt_chars+30h (13A17C0h)
这将是循环的开始。虽然在大多数高级语言中,将测试放在循环的顶部是很常见的,但在汇编语言中并不总是这样

 013A17B7 mov eax,dword ptr [i]
 013A17BA add eax,1
 013A17BD mov dword ptr [i],eax
这是(极度次优)汇编语言中的
i++
。它检索
i
的当前值,向其中添加一个值,然后将结果存储回
i

 013A17C0 mov eax,dword ptr [i]
 013A17C3 cmp eax,dword ptr [length]
 013A17C6 jge encrypt_chars+6Bh (13A17FBh) 
这基本上是
if(i==length)/*向前跳到您没有显示的某个代码*/
它检索
i
的值,并将其与
length
的值进行比较,如果
i
大于或等于
length
,则跳转到某个地方

如果您是用汇编语言手工编写的,通常会使用类似于
xor eax,eax
(或
sub eax,eax
)的方法将寄存器归零。在大多数情况下,您会从最大值开始,如果可能的话,倒计时到零(避免循环中的比较)。您当然不会将值存储到变量中,然后立即将其检索出来(公平地说,如果启用优化,编译器可能也不会这样做)

应用这一点,并将“变量”移动到寄存器中,我们最终会得到如下一般顺序:

    mov ecx, length
loop_top:
    ; stuff that wasn't pasted goes here
    dec ecx
    jnz loop_top

我将尝试用通俗易懂的英语来解释这一点:

 013A17AE  mov         dword ptr [i],0               ; Move into i, 0
 013A17B5  jmp         encrypt_chars+30h (13A17C0h)  ; Jump to check
 013A17B7  mov         eax,dword ptr [i]             ; Load i into the accumulator (register eax)
 013A17BA  add         eax,1                         ; Increment the accumulator
 013A17BD  mov         dword ptr [i],eax             ; and put that in it, effectively adding
; 1 to i.
check:
 013A17C0  mov         eax,dword ptr [i]             ; Move i into the accumulator
 013A17C3  cmp         eax,dword ptr [length]        ; Compare it to the value in 'length',
; setting flags
 013A17C6  jge         encrypt_chars+6Bh (13A17FBh)  ; Jump if it's greater or equal. This
; address is not in your code snippet

编译器更喜欢EAX进行算术运算。每个寄存器(在过去,我不知道这是否仍然是最新的)都有某种类型的操作,它执行起来更快。

下面是应该更优化的部分:
(注意:您的编译器应该执行此操作,因此您要么关闭了优化,要么循环体中的某些内容阻止了此优化)

查看您将值从内存来回移动到EAX的频率

您应该能够在循环开始时将“i”加载到EAX中一次,直接从EAX中运行整个循环,并在完成后将完成的值放回“i”中。
(除非代码中有其他内容阻止此操作)

无论如何,此代码来自调试生成。可以对其进行优化,但MS编译器为这种简单情况生成了非常好的代码


手动操作没有任何意义,只需在发布模式下重新构建它,并阅读列表以了解如何操作。

@John请使用“编辑”按钮在标签下面链接,为问题添加信息。这次我是为你做的。在效率方面有什么改进,例如使用更少的代码行等,但我要做的主要事情是了解它是如何工作的。谢谢。你不能只是“改进”循环。它必须根据具体情况进行改进。编译器已经对基本循环进行了优化。如果你想进一步改进它,你必须提供更多的上下文。对不起,我没有意识到,我目前正在大学学习,一项扩展任务是试着优化代码。我不知道它不能再进一步改进了,谢谢你谢谢你的回复。代码不完整(013A17C6和13A17FB之间发生的事情)整个循环体丢失。它是如何工作的?这里的汇编非常清楚-看起来你是在调试模式下编译的。很抱歉,我的编辑没有粘贴所有代码,谢谢你的帮助。
mov eax,dword ptr [i]    ; Go get "i" from memory, put it in register EAX
add eax,1                ; Add one to register EAX
mov dword ptr [i],eax    ; Put register EAX back in memory "i". (now one bigger)
mov eax,dword ptr [i]    ; Go get "i" from memory, put it in EAX again.