【问题标题】:String Arrays In Turbo AssemblerTurbo 汇编器中的字符串数组
【发布时间】:2021-05-22 19:30:04
【问题描述】:

如何在 Turbo Assembler 中创建一个字符串数组并使用索引来获取其中的特定值? 这是我的代码:

strs db 
     'Shirt$'
     'Pants$'
     'Socks$'

当我尝试运行它时,我收到“非法指令”错误

【问题讨论】:

  • 也许你想要一个指向字符串的指针数组?创建 3 个单独的字符串并将偏移量(地址)放入一个数组中。
  • 您忘记了操作数之间的逗号。大概这是一个汇编时语法错误,而不是您正在谈论的运行时#UD 异常?如果前一行以, 结尾,则将'Pants$' 单独放在一行上可能是有效的,但我不知道。您可能希望每行都有一个单独的db。 (当然,如果所有字符串的长度相同,那么这只有在没有指针表的情况下才可行,或者您可以填充它们。)

标签: arrays assembly x86-16 tasm


【解决方案1】:

您首先应该考虑什么是“字符串数组”:

strs db 'Shirt$'
     db 'Pants$'
     db 'Socks$'

(顺便说一句:db 在您的代码中的位置错误!)

... 等同于:

strs db 'Shirt$Pants$Socks$'

“字符串”表示内存中的某些字节包含可以解释为 ASCII 字符的值。

strs db 'Shirt$'

... 意思是:

地址strs处的字节具有代表字符S的值,地址strs+1处的字节具有代表字符h的值等等。

您首先必须考虑您真正想要拥有什么。你可能说:

"我的数组中的每个条目都应该能够保存一个最多 20 个字符长度的字符串(包括美元符号在内的 21 个字符)。"

在这种情况下,您可能决定内存位置strs...strs+20 保存第一个字符串,位置strs+21...strs+41 保存第二个字符串和@ 987654333@...strs+62第三个。

看起来像这样:

strs db 'Shirt$xxxxxxxxxxxxxxxPants$xxxxxxxxxxxxxxxSocks$xxxxxxxxxxxxxxx'

... 等同于:

strs db 'Shirt$xxxxxxxxxxxxxxx'
     db 'Pants$xxxxxxxxxxxxxxx'
     db 'Socks$xxxxxxxxxxxxxxx'

... 和以下相同:

strs       db 'Shirt$'
strsspare1 db 'xxxxxxxxxxxxxxx'
strs2      db 'Pants$'
strsspare2 db 'xxxxxxxxxxxxxxx'
strs3      db 'Socks$'
strsspare3 db 'xxxxxxxxxxxxxxx'

【讨论】:

    【解决方案2】:

    虽然另一个答案是正确的,但如果假设字符串数组的概念类似于像 C 这样的高级语言,那么你实际上是在处理指针数组(偏移量)内存中其他地方的字符串。您可以创建一个包含这些偏移量(指针)的数组,指向字符串本身。

    例如,C 程序可能会这样定义数组:

    #include <stdio.h>
    
    int main()
    {
        char *strarray[] = { "Shirt$", "Pants$", "Socks$" };
        printf("%s", strarray[2]);
        printf("%s", strarray[1]);
        return 0;
    }
    

    以下在功能上是等效的,但我们已命名字符串:

    #include <stdio.h>
    
    int main()
    {
        char *str1 = "Shirt$";
        char *str2 = "Pants$";
        char *str3 = "Socks$";
    
        char *strarray[] = { str1, str2, str3 };
        printf("%s", strarray[2]);
        printf("%s", strarray[1]);
        return 0;
    }
    

    后一个示例我将用于在 16 位汇编中重现类似的代码。它使比较汇编代码和C代码变得更加容易。

    以下是一个用 MASM/TASM/JWASM 汇编语言编写的 16 位 DOS 程序,它创建 3 个单独的字符串并为每个字符串创建一个指针(偏移量)数组。然后它索引指针数组以获取要打印的字符串的地址。此示例显示了 2 种访问数组的技术。一个索引在内存操作数中编码,另一个将索引放置在寄存器中(在这种情况下为BX)。

    .model small
    .stack 256
    
    .data
    str1 DB 'Shirt$'
    str2 DB 'Pants$'
    str3 DB 'Socks$'
    
    ; Create an array of pointers (offsets) to the strings in memory
    strarray DW OFFSET str1, OFFSET str2, OFFSET str3
    
    .code
    
    start:
        ; Setup the DS register to point at .data
        mov ax, @data
        mov ds, ax
    
        ; TYPE operator returns the size of an element in strarray.
        ; 2 in this case since we defined strarray with elements
        ; of type word (DW)
    
        ; Get the pointer stored in 3rd element of strarray to DX
        mov dx, strarray[2*(TYPE strarray)]
    
        ; Print the string using DOS function call
        mov ah, 9h
        int 21h
    
        ; Alternatively you can access the array element through
        ; a register like BX, SI, DI
    
        ; Get the offset of the 2nd element into BX
        mov bx, 1*(TYPE strarray)
        ; Get the pointer stored in 2nd element of strarray to DX
        mov dx, strarray[bx]
    
        ; Print the string using DOS function call
        mov ah, 9h
        int 21h
    
        ; Exit program
        mov ax, 4C00h
        int 21h
    
    end start
    

    使用 MASM 的 x86 Intel 语法,内存操作数看起来像数组索引,但它们不是。 [] 之间的值是 BYTES 中的索引。因此,您总是必须将索引乘以数组中元素的大小。 NEAR 指针是 16 位代码中的 2 个字节,因此每个元素的字节索引必须乘以 2。在上面的代码中,我使用返回数组元素大小的 TYPE 运算符。 strarray 定义为 DW(16 位字数组),因此返回值 2,因为每个元素的大小为 2 个字节。

    这段代码的输出是:

    SocksPants
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-04
      • 1970-01-01
      • 2021-03-04
      • 1970-01-01
      • 2012-09-11
      相关资源
      最近更新 更多