arrays - 如何索引汇编中的字符串

标签 arrays string assembly x86 c-strings

鉴于变量:

var1    db  "abcdefg", NULL

我将如何执行循环来导航每个字母?在 C++ 中,您会在循环内执行类似 var[x] 的操作,然后每次都增加 x。有任何想法吗?

最佳答案

在 C 和 C++ 中,字符串以 NUL 结尾。这意味着在字符串的末尾添加了一个 ASCII NUL 字符 (0),以便代码可以判断字符串的结束位置。 strlen函数从头开始遍历字符串,并不断循环,直到遇到此 NUL 字符。当它找到 NUL 时,它知道这是字符串的结尾,它返回从开头到 NUL 的字符数作为字符串的长度。

字符串文字(双引号中的内容)由 C/C++ 编译器自动以 NUL 结尾,因此:

"abcdefg"

等价于以下数组:
{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}

我提到这一点是因为 Peter Rader 在他的回答中提出了这一点,而你并没有真正理解他在说什么。但是,您似乎已经知道这一点,因为您在程序集声明中向字符串附加了一个 NUL 字符:
var1    db  "abcdefg", NULL

现在,一般来说,我们不使用标识符 NULL为了这。尤其不是在 C 中,其中 NULL定义为空指针。我们只使用字面量 0,因此定义为:
var1    db  "abcdefg", 0

但您的代码可能有效,假设 NULL在某处定义为 0。

所以你的设置都是正确的。现在你需要做的就是编写你的循环:
    mov  edx, OFFSET var1    ; get starting address of string

Loop:
    mov  al, BYTE PTR [edx]  ; get next character
    inc  edx                 ; increment pointer
    test al, al              ; test value in AL and set flags
    jz   Finished            ; AL == 0, so exit the loop

    ; Otherwise, AL != 0, so we fell through.
    ; Here, you can do do something with the character in AL.
    ; ...

    jmp  Loop                ; keep looping

Finished:

你说你熟悉CMP操作说明。在上面的代码中,我使用了 TEST而不是 CMP .你可以等效地写:
cmp  al, 0


test al, al

效率稍高一些,因为它是一条较小的指令,所以我只是习惯于在将寄存器的值与 0 进行比较的特殊情况下这样编写它。编译器也会生成此代码,因此很好熟悉它。

奖金聊天:表示字符串的另一种方法是将其长度(以字符为单位)与字符串本身一起存储。这就是 Pascal 语言的传统做法。这样,您就不需要字符串末尾的特殊 NUL 标记字符。相反,声明将如下所示:
var1    db  7, "abcdefg"

其中每个字符串的第一个字节是它的长度。 This has various advantages over the C style ,即您不必遍历整个字符串来确定其长度。当然,主要的缺点是字符串的长度被限制为 255 个字符,因为这就是 BYTE 的全部内容。

无论如何,预先知道长度,您不再检查 NUL 字符,您只是迭代与字符串中的字符相同的次数:
    mov  edx, OFFSET var1    ; get starting address of string
    mov  cl, BYTE PTR [edx]  ; get length of string

Loop:
    inc  edx                 ; increment pointer
    dec  cl                  ; decrement length
    mov  al, BYTE PTR [edx]  ; get next character
    jz   Finished            ; CL == 0, so exit the loop

    ; Do something with the character in AL.
    ; ...

    jmp  Loop                ; keep looping

Finished:

(在上面的代码中,我假设所有字符串的长度至少为 1 个字符。这可能是一个安全的假设,并且避免了在循环上方进行长度检查的需要。)

或者,您可以执行您提到的数组索引,但是如果要向前遍历字符串,则必须小心一点:
    mov   edx, OFFSET var1        ; get starting address of string
    movzx ecx, BYTE PTR [edx]     ; get length of string
    lea   edx, [ecx+1]            ; increment pointer by 1 + number of chars
    neg   ecx                     ; negate the length counter
Loop:
    mov   al, BYTE PTR [edx+ecx]  ; get next character

    ; Do something with the character in AL.
    ; ...

    inc   ecx
    jnz   Loop                     ; CL != 0, so keep looping

基本上,我们设置 EDX为了指向字符串的结尾,我们将计数器( ECX )设置为字符串长度的负数,然后我们通过索引 [EDX+ECX] 读取字符(因为我们否定了 ECX ,所以等价于 [EDX-ECX] )。

几乎可以肯定有一种比我在这里设法想到的更好(更聪明)的方法,但你应该明白这个想法。

关于arrays - 如何索引汇编中的字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44534685/

相关文章:

javascript - 无法读取未定义多维数组的属性 'push'

c - 如何改变C中数组的大小?

python - 如何用 dict ["key"中的值替换字符串中标有 {key} 的关键字]

android - 没有指令 stranih、lsreg、stream 的引用

assembly - 最多写两条指令来清除、设置和补充 AL 寄存器中的某些位

python - 如何以正确的格式在文本文件中写入两个 numpy 数组?

java - input.read() 函数。堆叠while循环

python - 如何从字符串的排列列表中分离元素?

assembly - 汇编和二进制有什么区别?

sql - 在 SQL 中,如何将一个数字乘以一个数组