从字符串数组中打印一个字符串

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-第个指针。
假设 iecx 那么

mov edx, DWORD PTR [arrayOfWords + ecx*4]
call writeString

因为每个指针都是四个字节。

如果要读取字符串i的字节j那么,假设jebxiecx:

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 串字符作为字符串。有两种方法可以把那串字符当作字符串数组。

  1. 在内存中搜索所需字符串的正确地址。在每个 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
    
  2. 构建指向字符串的指针数组:

    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。