【问题标题】:How to print a string in reverse order in a .COM executable?如何在 .COM 可执行文件中以相反的顺序打印字符串?
【发布时间】:2014-12-09 16:56:36
【问题描述】:

我刚刚开始学习汇编语言,我正在尝试以相反的顺序打印“hello world”,这意味着“dlrow olleh”。问题是我只得到第一个字母作为输出并且顺序仍然相同没有变化完全没有!作为一个新手,很多事情对我来说是未知的,我犯了很多错误,由于缺乏知识,我无法识别它们。所以任何有适当解释的答案都将不胜感激!这是我的代码:

name "hi" ; can anybody explain what is the use of this?

org 100h

jmp start       ; jump over data declaration

msg    db      "1Hello, World!",0;last character           
msg1   db      "1"

Mov   SI,13;lenght of the string
start: 

Mov  AL,msg[SI]
DEC SI 

Mov  ah ,0eh
int 10h   
mov BL,msg1

CMP msg[SI],BL;comparing to get the end of the string
je stop

jmp start                     

stop:
mov     ah, 0 
int     16h      ; wait for any key....
ret ; return to operating system.

我只得到第一个字母“1”的输出,但我希望以相反的顺序得到整个字符串

【问题讨论】:

  • 在调试器中单步执行时会发生什么?
  • 显示所有未知字符和空字符!
  • 请注意,这不会反转内存中的字符串,它只会在字符串上向后循环,一次打印一个字节。

标签: string assembly dos reverse x86-16


【解决方案1】:

一个简单的反转字符串的方法如下:

INCLUDE 'EMU8086.INC'
.MODEL SMALL
.STACK
.DATA
   ARR DB 10 DUB (?)   
   ;STR DB 0AH,0DH,'OUTPUT: $' 

.CODE
 MAIN PROC
    MOV AX, @DATA
    MOV DS, AX

    XOR BX, BX
    MOV CX, 0

  FOR: 
      MOV AH, 1
      INT 21H  

      CMP AL,0DH
      JE  PRINT   

      MOV ARR[BX], AL
      INC BX 
      INC CX
   JMP FOR


 PRINT:  
    MOV AH, 2       ;new line  
    MOV DL, 0AH
    INT 21H                 
    MOV DL, 0DH     ;curage return
    INT 21H   


  BACK: 
     CMP CX, 0
     JE FINISH
     DEC CX
     DEC BX  

     MOV AL, ARR[BX]

     MOV AH, 2       
     MOV DL, AL  
     INT 21H            
   JMP BACK

 FINISH:
    MOV AH,4CH
    INT 21H   

 MAIN ENDP

【讨论】:

  • 这在循环中有一堆浪费的指令。例如当您已经拥有 BX 时,您不需要将 CX 作为单独的计数器。
  • 您在一个现已删除的答案中询问如何写出更好的答案: 1. 用英语解释问题的答案是什么,以及答案中任何代码的意义。 2. 注释您的代码。对于未来的读者来说,了解您的代码为何如此运作会更有用。例如,请参阅有关如何使用div 的答案:stackoverflow.com/questions/38416593/…。或者这个关于打印整数的答案:stackoverflow.com/a/46301894/224132.
  • 另外,我的一些高度投票的答案在 IMO 中相当不错,但其中很少有人回答调试问题,因此格式不同。
  • Tnq @PeterCordes。我对你有义务。
【解决方案2】:

针对机器效率进行了优化。

它是为了简化您的问题,以便您更好地了解逻辑。

项目#1:评论每条指令,你会帮自己一个忙。

在这里,尝试一个带有循环的程序结构,像这样......

         Lea     Si, msg                 ;The target string
         Mov     Cx, 13                  ;The length of the string (be careful, but it'll probably work)
         Mov     Bx, Cx                  ;Think: the "base" can actually be an "offset into"

 The_Backwards_Loop:

         Mov     AL,[Bx+Si]              ;Get the "BXth" character in the string
         Mov     AH,0Eh                  ;Code for Bios to put that out to the screen
         Int     10h                     ;Bios puts char in AL onto the screen

         Dec     Bx                      ;Bx was at the Nth character, is now at N-1
         Loop    The_Backwards_Loop      ;And away we go through the rest of the string
                                         ;Note that Cx will dec just like we did Bx


         Mov     Ah, 0                   ;Code to wait for a keystroke
         Int     16h                     ;OS will now wait

         Ret                             ;And we are done, messing up Si, Bx, Ax, Cx, 

我对学习这些东西的建议......

  • 单步调试
  • 你会明白逻辑
  • 此时,请考虑“效率”
  • 一次尝试任何一种优化

至于这是“低效”,是的。

任何有效的东西都比任何无效的东西更有效。

再次重申,这个例子/建议的目的是先简化逻辑和代码结构,让你在脑海中有一个更清晰的画面;那么你可以“优化”

【讨论】:

  • 很好,但是当您已经让 BX 倒计时为零时,您不需要 CX 作为单独的循环计数器。只要BX 为非负数,在dec bx 之后使用jge 即可重新进入循环。 The loop instruction is slow 并且只能在优化代码大小时使用。 (然后只有当你不能使用 JCC 以更少的代码大小做同样的事情时)
【解决方案3】:
jmp start       ; jump over data declaratio
...
Mov   SI,13;lenght of the string
start: 

这就是问题所在——你没有初始化寄存器si

你需要使用类似的东西:

jmp init       ; jump over data declaratio
...
init:
Mov   SI,13;lenght of the string
start: 

【讨论】:

  • 我同意这绝对是个问题。不过,我会期待不同的行为。
  • 如果 SI 的值为 0,这正是我所期望的行为。我不确定它是否保证为 0,或者有一些不确定的值。
  • @RobertHarvey si 通常为 0,所以这个应用程序会在大多数计算机上显示“1”,但后来不是很清楚 - dec si 将使其变为 0xffff 并将比较 jmp 然后bl 的 PSP 的最后一个字节,我想最后一个字节将全为零,所以它们被显示,但不可见,最后这个循环可以停止,因为 je
猜你喜欢
  • 1970-01-01
  • 2016-02-17
  • 2022-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多