使用汇编语言程序交换两个字符串变量的内容

时间:2017-05-23 08:10:41

标签: assembly

我是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

如果我可以在此处进行任何更改以获得准确的输出,请告诉我。

1 个答案:

答案 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

现在您有两个标签NUM1NUM2指向同一个字节,因此您拥有&#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; (与阅读英特尔指令参考指南相比,您仍应经常阅读该指南)。