在 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
but
test al, al
效率稍高一些,因为它是一条较小的指令,所以我只是习惯在将寄存器的值与 0 进行比较的特殊情况下这样编写。编译器也会生成此代码,所以它很好熟悉它。
奖金闲聊:表示字符串的另一种方法是将其长度(以字符为单位)与字符串本身一起存储。这就是 Pascal 语言传统上所做的事情。这样,您就不需要在字符串末尾使用特殊的 NUL 标记字符。相反,该声明将如下所示:
var1 db 7, "abcdefg"
其中每个字符串的第一个字节是它的长度。与 C 风格相比,这具有多种优点 https://www.joelonsoftware.com/2001/12/11/back-to-basics/,即您不必迭代整个字符串来确定其长度。当然,主要缺点是字符串的长度限制为 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:
(在上面的代码中,我假设所有字符串都是minimum长度为 1 个字符。这可能是一个安全的假设,并且避免了在循环上方进行长度检查的需要。)
或者,您可以执行您提到的数组索引,但如果您想迭代,则必须小心一点forwards通过字符串:
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
指向end的字符串,我们设置计数器(ECX
)到negative字符串的长度,然后我们通过索引读取字符[EDX+ECX]
(因为我们否定了ECX
,相当于[EDX-ECX]
).
几乎可以肯定,有一种比我在这里想到的更好(更聪明)的方法来做到这一点,但你应该明白这个想法。