我是AL编程新手。我试图交换两个字符串变量的内容。我有一个代码与我交换两个内存变量。这是代码 -
DATA SEGMENT
NUM1 DB 9H
NUM2 DB 7H
ENDS
CODE SEGMENT
ASSUME DS:DATA CS:CODE
START:
MOV AX,DATA
MOV DS,AX
MOV AL,NUM1
MOV BL,NUM2
XCHG AL,NUM2
XCHG BL,NUM1
MOV AH,4CH
INT 21H
ENDS
END START
如果我可以在此处进行任何更改以获得准确的输出,请告诉我。
答案 0 :(得分:1)
MOV AL,NUM1
MOV BL,NUM2
XCHG AL,NUM2
XCHG BL,NUM1
可以缩短为(完成时:相同的内存,不同的寄存器):
MOV AL,[NUM1]
XCHG AL,[NUM2]
MOV [NUM1],AL
但实际上这个更长的版本应该表现得更好(XCHG
可能是非常昂贵的指令,因为它通常与LOCK
前缀一起使用来同步多处理器PC中的东西,它不被使用几十年来编译器交换"交换"值,因此它没有针对现代x86 CPU进行优化):
MOV AL,[NUM1]
MOV BL,[NUM2]
MOV [NUM2],AL
MOV [NUM1],BL
; when finished: same memory, but swapped AL<->BL
这就是关于BYTE&#34;变量&#34;。我建议你实际上不再考虑NUM1
作为变量,而是意识到它只是符号标签,一个存储器地址,其中放置了以下字节的机器代码。并且后面的字节由DB 9h
定义,即8位值9
。这就是为什么我更喜欢原始的完整英特尔语法的原因,使用方括号编写mov al,[NUM1]
以便在快速浏览源代码时显而易见,该指令正在访问内存并且NUM1
是地址。
更多例子,为什么&#34;变量&#34;思维方式会使它过于复杂化:
NUM1:
NUM2: DB 9
现在您有两个标签NUM1
和NUM2
指向同一个字节,因此您拥有&#34;别名&#34;单个&#34;变量&#34;。
最后是字符串...
InputString DB "Hello$"
没有&#34;字符串&#34;在CPU中,InputString
不能是&#34;字符串变量&#34;。它仅标记定义的下一个字节,机器代码中的下一个定义字节的值为'H'
,等于72
(检查ASCII表是否包含特定ASCII字符的值)。该行将编译为6个字节的机器码,其中包含(hexa)值:
48 65 6C 6C 6F 24
所以到#34;交换两个字符串的内容&#34;首先需要知道的是,两个目标内存位置都有足够的字节保留。例如:
String1 DB "a"
String2 DB "bc"
如果您尝试交换内容,则设置为灾难,因为&#34; String1&#34;仅保留1个字节。因此,当您将"bc"
写入其中时,'c'
实际上会落在地址String2
如果你知道有足够的内存保留给&#34;字符串&#34;,你需要将字节内容从一个复制到另一个,反之亦然,你实际上甚至可以忽略字符串的实际长度,并且只是逐字节地交换两个缓冲区的总内容(如buffer1 db 100 dup (?)
buffer2 db 100 dup (?)
,然后在两者之间交换100个字节,而不是关心内部的内容)。或者你可以通过终止条件来优化它,当你达到&#34;字符串结束时#34;标记在较长的一个。
另请注意,程序集中没有字符串类型,因此如何标记字符串的结尾取决于代码。由int 21h,9
服务完成的DOS输出确实使用了字符值'$'
,但您也可以使用以零值终止的类似C的字符串,甚至使用旧的Pascal方式来保留字符串的第一个字节对于长度值,因此Pascal中的a = "Hello";
以字节05 48 65 6C 6C 6F
存储在内存中。如果要使用int 21h,9
服务输出结果字符串,则必须在其末尾覆盖'$'
个终结符。 (还要记住字符串的终结符实际上是它的一部分,因此100字节的保留内存对于零终止的长度为99个字符的字符串来说足够大。)
继续使用调试器来监视寄存器和内存中的值,它们如何随执行的每条指令而改变,它将极大地加快您学习的速度,因为它非常&#34;视觉&#34; (与阅读英特尔指令参考指南相比,您仍应经常阅读该指南)。