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编程)。