扩展我的评论:更有效的循环结构是:
data segment
string db "proce'so'r"
stringlen equ $-string ; subtract current string's address from current address
ends
start:
mov ax, data
mov ds, ax ; Assuming rkhb is correct about segments
lea di, string
mov cx, stringlen ; having the assembler generate this constant from the length of the string prevents bugs if you change the string
;; if stringlen can be zero:
; test cx,cx
; jz end
;; .labels are "local" and don't end up as symbols in the object file, and don't have to be unique across functions
;; emu8086 may not support them, and this Q is tagged as 8086, not just 16bit DOS on a modern CPU.
print_loop:
mov dl, [di]
mov ah, 02h ; If int21h doesn't clobber ah, this could be hoisted out of the loop. IDK.
int 21h
inc di
dec cx
jg print_loop ; or jne
end:
; Or save a register (and the mov to initialize it) with
; cmp di, offset string+stringlen
; jb print_loop
;; loop print_loop ; or save instruction bytes, but slower on modern CPUs
mov ax, 4c00h
int 21h
处理字符串的一种更常见的方法是用零字节终止它们。所以循环边界是test dl,dl / jnz
,不需要计数器。
另外,请注意,通常si
用作源指针和目标指针。di
您可以在跳过某个字符的同时复制字符串
mov dl, [si]
inc si
cmp dl, '\'' ; or write the value as a hex constant instead of a character literal
je nocopy
mov [di], dl
inc di
nocopy:
作为循环的一部分。在循环开始时,您希望 si 指向输入字符串中的第一个字符,并希望 di 指向足够大以保存结果的缓冲区。要跳过的字符可以在寄存器中,而不是硬编码为cmp
.
如果你真的想节省代码字节,以牺牲现代 CPU 的速度为代价,你可以使用字符串移动指令lodsb
/ stosb
,除了它们加载到 / 存储自al
.