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