我想计算数组中 1 的个数(使用 MASM32)。在第一次迭代中,我在 EAX
中得到了一些奇怪的值。我得到的不是 00000000,而是 00010000。因此,计数器 ECX
中的值也不正确。
.386
.model small
.data
var1 dw 0,1,1
.code
main PROC
LEA ESI, var1
MOV EBX, 3
MOV ECX, 0
L1:CMP EBX, 0
JE L3
MOV EAX, [ESI]
CMP EAX, 0
JE L2
INC ECX
L2:DEC EBX
ADD ESI, 2
JMP L1
L3:INVOKE ExitProcess, 0
main ENDP
END main
看这张图,在 EAX
中得到 00010000 而不是 00000000 因为 [ESI]
的内容在开始时是 0
最佳答案
您将 var1
定义为 word(16 位)而不是 dword,但您加载的是 dword (32 位)因为你加载到 eax
这是一个 32 位大小的寄存器,所以你正在获取内存中的下一个单词(即 1
)你的双字的上半部分。看这个例子:
x dw 1
y dw 2
z dw 3
# resulting memory layout:
# 01 00 02 00 03 00
# \_x_/ \_y_/ \_z_/
mov ax, [x] # you get 0001
mov eax, [x] # you get 00020001 !! because you are reading x AND y
movzx eax, word ptr [x] # you get 00000001
# 01 00 02 00 03 00
# \_x_/ \_y_/ \_z_/
# \ax_/
# \___eax___/
mov ax, [y] # you get 0002
mov eax, [y] # you get 00030002 !! because you are reading y AND z
movzx eax, word ptr [y] # you get 00000002
# 01 00 02 00 03 00
# \_x_/ \_y_/ \_z_/
# \ax_/
# \___eax___/
在你的例子中,它不是另一个命名变量,而是 var1
的第二部分(你有 var1 dw 0,1,1
所以你定义了三个值为 0000 的词, 0001, 0001 - 但与上面的示例一样适用于此)。
var1 dw 0,1,1
# 00 00 01 00 01 00
# \___/ \___/ \___/
# \var1 \ \var1+4
# \var1+2
# \ax_/
# \___eax___/
因此,要么使用 dd
而不是 dw
使您的变量成为双字(然后将 esi
增加 4 而不是 2),或通过将单词存储到较小的寄存器(如 ax
)或使用 movzx
(或 movsx
,如果你需要一个有符号的值)和 word ptr
,扩展值以填充整个寄存器。
var1 dd 0,1,1
# 00 00 00 00 01 00 00 00 01 00 00 00
# \__var1___/ \_var1+4__/ \_var1+8__/
# \___eax___/
请注意,如果您决定使用 ax
,请记住将数据加载到其中不会修改 eax
的上半部分,它会保持其先前的值,所以你不能写入 ax
然后从 eax
读取,因为你会再次在上半部分得到意想不到的东西。然后,您还需要执行 cmp ax, 0
而不是 cmp eax, 0
。您需要始终清楚自己正在读或写的内容(以及多少)。
关于assembly - 计算 DW 数组中等于 1 的元素个数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69390039/