计算 DW 数组中等于 1 的元素个数
Counting number of elements equal to 1 in DW array
我想计算数组中 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
。您需要始终清楚自己正在读或写什么(以及多少)。
我想计算数组中 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
。您需要始终清楚自己正在读或写什么(以及多少)。