Arrays 如何在程序集中索引字符串

Arrays 如何在程序集中索引字符串,arrays,string,assembly,x86,c-strings,Arrays,String,Assembly,X86,C Strings,给定变量: var1 db "abcdefg", NULL 如何执行循环来导航每个字母?在C++中,你会在循环中做一些类似var [x]的事情,然后每次增加X。有什么想法吗? < P>在C和C++中,字符串是NUL终止的。这意味着将ASCII NUL字符(0)添加到字符串的末尾,以便代码可以判断字符串的结尾。strlen函数从头到尾遍历字符串,并保持循环,直到遇到此NUL字符。当它找到NUL时,它知道这是字符串的结尾,并返回从开头到NUL的字符数作为字符串的长度 字符串文本(双引号中的

给定变量:

var1    db  "abcdefg", NULL

如何执行循环来导航每个字母?在C++中,你会在循环中做一些类似var [x]的事情,然后每次增加X。有什么想法吗?

< P>在C和C++中,字符串是NUL终止的。这意味着将ASCII NUL字符(0)添加到字符串的末尾,以便代码可以判断字符串的结尾。
strlen
函数从头到尾遍历字符串,并保持循环,直到遇到此NUL字符。当它找到NUL时,它知道这是字符串的结尾,并返回从开头到NUL的字符数作为字符串的长度

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

"abcdefg"
等效于以下数组:

{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
我提到这一点是因为彼得·雷德在他的回答中提出了这一点,而你并不真正理解他在说什么。但是,当您在程序集声明中将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
但是

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


额外聊天:表示字符串的另一种方法是将其长度(以字符为单位)与字符串本身一起存储。这是帕斯卡语的传统做法。这样,您就不需要在字符串末尾使用特殊的NUL sentinel字符。相反,宣言应该是这样的:

var1    db  7, "abcdefg"
其中每个字符串的第一个字节是其长度,也就是说,您不必遍历整个字符串来确定其长度。当然,主要的缺点是字符串的长度限制在255个字符以内,因为一个字节只能容纳255个字符

无论如何,使用预先知道的长度,您不再检查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:
    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
(在上面的代码中,我假设所有字符串的长度至少为1个字符。这可能是一个安全的假设,避免了在循环上方执行长度检查的需要。)

或者,您也可以执行前面提到的数组索引,但如果要向前迭代字符串,则必须小心一点:

    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:
    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]


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

我认为问题更多的是如何索引到数组中。因此,我认为使用
mov-al、[var1+edx]
的简单解决方案应该是合适的。嗯,也许吧。它确实说,“我将如何执行循环来导航每个字母?”,所以这就是我回答的部分。当然,如果您只想获取其中一个字符,那么,
mov al,BYTE PTR[var1+index]
(其中index是立即数或包含该值的寄存器)将起作用。我不确定我应该把答案写得更长。:-)mov al,0,rep scasb?是的,
rep scasb
可以通过搜索终止的NUL字符来查找字符串的长度。用汇编语言实现strlen是一种(极其)低效的方法(除非您是为8088编程)。