我需要在 8086* 中编写以下 C 代码片段 组装尽可能短(小于 10 字节),但我只能设法用 12 个字节写它。
有什么想法吗?
while (ax) {
bx--;
ax &= ax-1;
}
您尝试的操作称为人口计数,即计算寄存器中的设置位数。
在较新的CPU中实际上只有一个指令。而且由于瞄准原始 8086 在 2018 年真的不是那么有趣。
简单的答案是:
f3 0f b8 c0 popcnt eax,eax
29 c3 sub ebx,eax
6 字节,如果您愿意在ebx
中允许正值并且可以假设/确保 ebx 开始时为零,则可以减少到 4。
请注意,没有必要使用 16 位寄存器,已经很多年没有了。
如果您希望代码在原始 8086(不支持popcnt
)上运行,则必须保留循环。
以下非常简单的代码需要 12 个字节:
85 c0 test ax,ax ;is AX zero?
74 08 je <done> ;yes, bail out
<loop>:
4b dec bx ;bx--
89 c1 mov cx,ax
49 dec cx ;cx = ax - 1
21 c8 and ax,cx ;ax = ax & (ax-1)
75 f8 jne <loop> ;repeat until done
<done>:
您可以通过以效率稍低的方式计算位数来将其减少到 9 个字节。在这里,我们简单地测试所有 16 位 ax。
<loop>:
d1 e0 shl ax,1 ;MSb to carry flag (CF)
83 db 00 sbb bx,0 ;bx=bx-CF
85 c0 test ax,ax ;is AX zero?
75 f9 jnz <loop> ;if not then loop until done
诀窍是理解代码的作用,然后以不同的方式重新表述。