我试图理解此递归代码,但对add bx, 2
的目的感到困惑。我已经在相关行上打上了标记。据我了解,我们必须使用值将指向数组的指针增加,但是为什么我们要加2而不是1?
.model small
.stack 100
.data
arr dw 38, 39, 90, 94, 13, 24, 53, 59, 63
size dw 9
result dw ?
.code
func proc
push bp
mov bp, sp
push ax
push bx
push cx
push dx
mov cx, [bp+4]
mov bx, [bp+6]
mov ax, [bx]
cmp cx, 1
ja more
mov [bp+6], ax
jmp done
more:
**add bx, 2**
push bx
dec cx
push cx
call func
pop dx
cmp dx, ax
jg greater
mov [bp+6], ax
jmp done
greater:
mov [bp+6], dx
done:
pop dx
pop cx
pop bx
pop ax
pop bp
ret 2
func endp
答案 0 :(得分:4)
据我了解,我们必须使用值将指向数组的指针增加,但是为什么我们要加2而不是1?
如果我理解正确,gap' :: Eq a => a -> a -> [a] -> Maybe Int
gap' x y ls
| null ls' = Nothing
| head ls' == y = Nothing
| otherwise = elemIndex y ls'
where
ls' = dropWhile (\t -> t /= x && t /= y) ls
指向包含16位值的数组中元素的地址。
指令BX
向您显示元素是16位值,而不是8位或32位值。 16位值是2个字节长。
在大多数CPU(有TMS 320或TMS 9900之类的例外)上,如果元素的长度为mov ax, [bx]
个字节,则数组中两个元素的地址之差为n
。
因此,如果n
是包含16位值的数组中元素的地址,而x
是下一个元素的地址,则y
。
因此必须将两个添加到y-x=2
中以获取下一个元素的地址。
答案 1 :(得分:1)
请注意之后的push bx
/ ... / call func
:这是一个递归函数,它将bx+2
传递给下一个调用。
我认为BX已被用作指针,并且有一个arr
,它是“单词”(2个字节)的数组,因此几乎可以肯定是指针增量。
这看上去非常效率低下;它只是单个递归,因此很容易将其编写为循环。 C中的do { something with *p++; } while(--cx);
,即底部为dec cx / jnz
的循环。
此外,分支非常愚蠢:它可以在保存尽可能多的寄存器之前更早地检查递归终止条件。使用jmp
可以使jna done
脱离函数的正常路径。也许需要在函数末尾跳转到一个特殊的块,在特殊情况下将2个跳转放在特殊情况下,但这仍然比在主路径上进行2个跳转要好。
将内容存储/重新加载到[bp+6]
也很奇怪。该函数是否通过修改其在堆栈上的一个args返回?通话后,它基于pop dx
的样子。我希望对此进行有意的混淆,或将其写为优化的起点,因为这看起来过于复杂。
基于分支目标名称,我假设它只是在给定指针和长度的情况下在数组中找到最大带符号的单词。这样做很简单,而且循环效率更高。