鉴于变量:
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/