从字符串数组中打印一个字符串
Print one string from arrays of strings
如何在汇编程序中创建字符串数组并使用它们?
我试试:
arrayOfWords BYTE "BICYCLE", "CANOE", "SCATEBOARD", "OFFSIDE", "TENNIS"
然后我想打印第二个字,但它不起作用
mov edx, offset arrayOfWords[2]
call WriteString
但他把我印在全世界。
arrayOfWords BYTE "BICYCLE", "CANOE", "SCATEBOARD", "OFFSIDE", "TENNIS"
只是另一种写法
arrayOfWords BYTE "BICYCLECANOESCATEBOARDOFFSIDETENNIS"
这远不是数组。
此外 mov edx, offset arrayOfWords[2]
不是数组索引。
汇编中的括号用于表示 addressing mode,而不是数组索引。
这就是为什么我不能停止强调 NOT1 使用语法 <symbol>[<displacement>]
(你的 arrayOfWords[2]
) - 它[<symbol> + <displacement>]
是一种非常愚蠢和令人困惑的写法(在你的例子中是 [arrayOfWords + 2]
)。
你可以看到 mov edx, OFFSET [arrayOfWords + 2]
(在我看来写成 mov edx, OFFSET arrayOfWords + 2
更清楚,因为指令没有访问任何内存)只是加载 edx
的地址C BICYCLE 中的字符(大字符串的第三个字符)。
MASM 有很多我从来没有费心学习的高级机制,但是快速浏览了脚注中链接的手册后,它似乎没有对数组的高级支持。
这是一件好事,我们可以使用更干净的组件。
字符串数组不是连续的字符串块,它是指向字符串的指针的连续块。
字符串可以在任何地方。
arrayOfWords DWORD OFFSET strBicycle,
OFFSET strCanoe,
OFFSET strSkateboard,
OFFSET strOffside,
OFFSET strTennis
strBicycle BYTE "BICYCLE",0
strCanoe BYTE "CANOE", 0
strSkateboard BYTE "SKATEBOARD", 0
strOffside BYTE "OFFSIDE", 0
strTennis BYTE "TENNIS", 0
记住:数组的优点是访问时间恒定;如果将字符串放在一起,我们会得到一个更紧凑的数据结构,但没有恒定的访问时间,因为除了扫描整个字符串之外没有办法知道字符串从哪里开始。
对于指针,我们有恒定的访问时间,一般来说,我们要求数组的所有元素都是同质的,就像指针一样。
要加载数组中 i-th2 字符串的地址,我们只需读取 i-第个指针。
假设 i 在 ecx
那么
mov edx, DWORD PTR [arrayOfWords + ecx*4]
call writeString
因为每个指针都是四个字节。
如果要读取字符串i的字节j那么,假设j 在 ebx
和 i 在 ecx
:
mov esi, DWORD PTR [arrayOfWords + ecx*4]
mov al, BYTE PTR [esi + ebx]
使用的寄存器是任意的。
1 尽管 Microsoft 在其 MASM 6.1 manual 中写道:
Referencing Arrays
Each element in an array is referenced with an index number, beginning with zero. The array index appears in brackets after the array name, as in
array[9]
Assembly-language indexes differ from indexes in high-level languages, where the index number
always corresponds to the element’s position. In C, for example, array[9] references the array’s
tenth element, regardless of whether each element is 1 byte or 8 bytes in size.
In assembly language, an element’s index refers to the number of bytes between the element and the start of the array.
2 从零开始计数。
arrayOfWords
不是数组,甚至不是变量。它只是一个标签,告诉汇编程序在哪里可以找到某些东西,在本例中是一堆字符。 Irvine 的 WriteString
期望 null-terminated 串字符作为字符串。有两种方法可以把那串字符当作字符串数组。
在内存中搜索所需字符串的正确地址。在每个 null 处开始一个新字符串。
INCLUDE Irvine32.inc
.DATA
manyWords BYTE "BICYCLE", 0
BYTE "CANOE", 0
BYTE "SCATEBOARD", 0
BYTE "OFFSIDE", 0
BYTE "TENNIS", 0
BYTE 0 ; End of list
len equ $ - manyWords
.CODE
main PROC
mov edx, 2 ; Index
call find_str ; Returns EDI = pointer to string
mov edx, edi
call WriteString ; Irvine32: Write astring pointed to by EDX
exit ; Irvine32: ExitProcess
main ENDP
find_str PROC ; ARG: EDX = index
lea edi, manyWords ; Address of string list
mov ecx, len ; Maximal number of bytes to scan
xor al, al ; Scan for 0
@@:
sub edx, 1
jc done ; No index left to scan = string found
repne scasb ; Scan for AL
jmp @B ; Next string
done:
ret
find_str ENDP ; RESULT: EDI pointer to string[edx]
END main
构建指向字符串的指针数组:
INCLUDE Irvine32.inc
.DATA
wrd0 BYTE "BICYCLE", 0
wrd1 BYTE "CANOE", 0
wrd2 BYTE "SCATEBOARD", 0
wrd3 BYTE "OFFSIDE", 0
wrd4 BYTE "TENNIS", 0
pointers DWORD OFFSET wrd0, OFFSET wrd1, OFFSET wrd2, OFFSET wrd3, OFFSET wrd4
.CODE
main PROC
mov ecx, 2 ; Index
lea edx, [pointers + ecx * 4] ; Address of pointers[index]
mov edx, [edx] ; Address of string
call WriteString
exit ; Irvine32: ExitProcess
main ENDP
END main
顺便说一句:与其他语言一样,索引从 0 开始。第二个字符串是索引 = 1,第三个索引 = 2。
如何在汇编程序中创建字符串数组并使用它们?
我试试:
arrayOfWords BYTE "BICYCLE", "CANOE", "SCATEBOARD", "OFFSIDE", "TENNIS"
然后我想打印第二个字,但它不起作用
mov edx, offset arrayOfWords[2]
call WriteString
但他把我印在全世界。
arrayOfWords BYTE "BICYCLE", "CANOE", "SCATEBOARD", "OFFSIDE", "TENNIS"
只是另一种写法
arrayOfWords BYTE "BICYCLECANOESCATEBOARDOFFSIDETENNIS"
这远不是数组。
此外 mov edx, offset arrayOfWords[2]
不是数组索引。
汇编中的括号用于表示 addressing mode,而不是数组索引。
这就是为什么我不能停止强调 NOT1 使用语法 <symbol>[<displacement>]
(你的 arrayOfWords[2]
) - 它[<symbol> + <displacement>]
是一种非常愚蠢和令人困惑的写法(在你的例子中是 [arrayOfWords + 2]
)。
你可以看到 mov edx, OFFSET [arrayOfWords + 2]
(在我看来写成 mov edx, OFFSET arrayOfWords + 2
更清楚,因为指令没有访问任何内存)只是加载 edx
的地址C BICYCLE 中的字符(大字符串的第三个字符)。
MASM 有很多我从来没有费心学习的高级机制,但是快速浏览了脚注中链接的手册后,它似乎没有对数组的高级支持。
这是一件好事,我们可以使用更干净的组件。
字符串数组不是连续的字符串块,它是指向字符串的指针的连续块。
字符串可以在任何地方。
arrayOfWords DWORD OFFSET strBicycle,
OFFSET strCanoe,
OFFSET strSkateboard,
OFFSET strOffside,
OFFSET strTennis
strBicycle BYTE "BICYCLE",0
strCanoe BYTE "CANOE", 0
strSkateboard BYTE "SKATEBOARD", 0
strOffside BYTE "OFFSIDE", 0
strTennis BYTE "TENNIS", 0
记住:数组的优点是访问时间恒定;如果将字符串放在一起,我们会得到一个更紧凑的数据结构,但没有恒定的访问时间,因为除了扫描整个字符串之外没有办法知道字符串从哪里开始。
对于指针,我们有恒定的访问时间,一般来说,我们要求数组的所有元素都是同质的,就像指针一样。
要加载数组中 i-th2 字符串的地址,我们只需读取 i-第个指针。
假设 i 在 ecx
那么
mov edx, DWORD PTR [arrayOfWords + ecx*4]
call writeString
因为每个指针都是四个字节。
如果要读取字符串i的字节j那么,假设j 在 ebx
和 i 在 ecx
:
mov esi, DWORD PTR [arrayOfWords + ecx*4]
mov al, BYTE PTR [esi + ebx]
使用的寄存器是任意的。
1 尽管 Microsoft 在其 MASM 6.1 manual 中写道:
Referencing Arrays
Each element in an array is referenced with an index number, beginning with zero. The array index appears in brackets after the array name, as in
array[9]
Assembly-language indexes differ from indexes in high-level languages, where the index number always corresponds to the element’s position. In C, for example, array[9] references the array’s tenth element, regardless of whether each element is 1 byte or 8 bytes in size. In assembly language, an element’s index refers to the number of bytes between the element and the start of the array.
2 从零开始计数。
arrayOfWords
不是数组,甚至不是变量。它只是一个标签,告诉汇编程序在哪里可以找到某些东西,在本例中是一堆字符。 Irvine 的 WriteString
期望 null-terminated 串字符作为字符串。有两种方法可以把那串字符当作字符串数组。
在内存中搜索所需字符串的正确地址。在每个 null 处开始一个新字符串。
INCLUDE Irvine32.inc .DATA manyWords BYTE "BICYCLE", 0 BYTE "CANOE", 0 BYTE "SCATEBOARD", 0 BYTE "OFFSIDE", 0 BYTE "TENNIS", 0 BYTE 0 ; End of list len equ $ - manyWords .CODE main PROC mov edx, 2 ; Index call find_str ; Returns EDI = pointer to string mov edx, edi call WriteString ; Irvine32: Write astring pointed to by EDX exit ; Irvine32: ExitProcess main ENDP find_str PROC ; ARG: EDX = index lea edi, manyWords ; Address of string list mov ecx, len ; Maximal number of bytes to scan xor al, al ; Scan for 0 @@: sub edx, 1 jc done ; No index left to scan = string found repne scasb ; Scan for AL jmp @B ; Next string done: ret find_str ENDP ; RESULT: EDI pointer to string[edx] END main
构建指向字符串的指针数组:
INCLUDE Irvine32.inc .DATA wrd0 BYTE "BICYCLE", 0 wrd1 BYTE "CANOE", 0 wrd2 BYTE "SCATEBOARD", 0 wrd3 BYTE "OFFSIDE", 0 wrd4 BYTE "TENNIS", 0 pointers DWORD OFFSET wrd0, OFFSET wrd1, OFFSET wrd2, OFFSET wrd3, OFFSET wrd4 .CODE main PROC mov ecx, 2 ; Index lea edx, [pointers + ecx * 4] ; Address of pointers[index] mov edx, [edx] ; Address of string call WriteString exit ; Irvine32: ExitProcess main ENDP END main
顺便说一句:与其他语言一样,索引从 0 开始。第二个字符串是索引 = 1,第三个索引 = 2。