【问题标题】:Assembly, printing ascii number组装,打印ASCII码
【发布时间】:2013-03-15 07:33:44
【问题描述】:

我的汇编代码有问题。我想打印存储在寄存器 cx 中的数字,但是当我尝试打印它时,它打印的是 ascii 字符而不是 ascii 数字,所以我决定编写一个将 ascii char 转换为 ascii 值的过程。 问题是,当我尝试调用该程序时,程序冻结,我必须重新启动 dosbox。有谁知道这段代码有什么问题?谢谢。

P4      PROC                
            MOV AX,CX           ;CX = VALUE THAT I WANT TO CONVERT
            MOV BX,10           
    ASC2:
            DIV BX              ;DIV AX/10
            ADD DX,48           ;ADD 48 TO REMAINDER TO GET ASCII CHARACTER OF NUMBER 
            PUSH AX             ;SAVE AX
            MOV AH,2            ;PRINT REMAINDER STORED IN DX
            INT 21H             ;INTERRUP
            POP AX              ;POP AX BACK
            CMP AX,0            
            JZ EXTT             ;IF AX=0, END OF THE PROCEDURE
            JMP ASC2            ;ELSE REPEAT
    EXTT:
            RET
    P4      ENDP

【问题讨论】:

  • 分割前需要清除DXDIV BXDX:AX 除以 BX
  • 除了@user786653 所说的之外,您还有一个问题是最终会以相反的顺序打印数字。例如。 123 将与您的代码一起打印为 321。

标签: assembly x86 ascii x86-16


【解决方案1】:

这样的东西更适合打印十进制值(新代码是小写的):

        mov byte [buffer+9],'$'
        lea si,[buffer+9]

        MOV AX,CX           ;CX = VALUE THAT I WANT TO CONVERT
        MOV BX,10         
ASC2:
        mov dx,0            ; clear dx prior to dividing dx:ax by bx
        DIV BX              ;DIV AX/10
        ADD DX,48           ;ADD 48 TO REMAINDER TO GET ASCII CHARACTER OF NUMBER 
        dec si              ; store characters in reverse order
        mov [si],dl
        CMP AX,0            
        JZ EXTT             ;IF AX=0, END OF THE PROCEDURE
        JMP ASC2            ;ELSE REPEAT
EXTT:
        mov ah,9            ; print string
        mov dx,si
        int 21h
        RET

buffer: resb 10

它不是直接打印每个字符,而是以相反的顺序将字符添加到缓冲区中。对于值 123,它将在缓冲区 [8] 处添加“3”,在缓冲区 [7] 处添加“2”,在缓冲区 [6] 处添加“1” - 因此,如果您随后打印从缓冲区 + 6 开始的字符串,则会得到“123 "。
我使用的是 NASM 语法,但希望它应该足够清楚。

【讨论】:

  • 嘿!我可以得到一些帮助吗?我试图将这段代码添加到我的代码中,但它向我抛出了错误undefined var: byte [buffer+9] 是有道理的,但自从我学习汇编的第一天以来就无法弄清楚,我已经陷入了“如何将十进制转换为字符串并打印它”在屏幕上”
【解决方案2】:

正如迈克尔在他的代码中所写,您需要清除 DX ,即在除法之前将其设为 0。

但是如果你问我,你是否只需要以 ASCII 形式显示一个数字(当你想显示一个数字时不要得到笑脸)。在内部将值转换为 ASCII 可能非常不方便。

为什么不直接使用在程序开始时定义的数组,其中包含数字的所有 ASCII 值,然后选择对应的那个。

例如。 DB arr '0123456789' 并将每个数字与特定位置进行比较并打印出来。自从我用 8086 编码以来已经很长时间了,但我记得在一个程序中使用了这个逻辑,该程序需要我打印一个十六进制数字的 ASCII 值。所以我使用了一个包含0123456789ABCDEF 的数组,它运行良好。

只有我的两分钱。因为你只想要结果。你如何计算它并不重要。

【讨论】:

    【解决方案3】:

    我认为我应该对此发布更新。这篇文章确实帮助我找到了一种获取 PHP CLI 脚本的关键输入的方法。我在任何地方都找不到 Windows/DOS 解决方案,所以我选择了外部程序。

    我使用的是一个非常旧版本的 a86 汇编器,所以代码非常基本。

    (以及如何关闭“运行代码片段”?)

    ;Key input for scripts that can use some "shell" function.
    ;Waits for a keypress then returns a string "key:scan"
    ;if "key" is 0 then you can check "scan" for arrow keys
    ;or other non-ASCII keys this way.
    
      mov ah,0
      int 16h
    
      push ax
      mov ah,0
      mov cx,ax
      call ASC
    
      mov dx,':'
      call COUT
      pop ax
      shr ax,8
      mov ah,0
      mov cx,ax
      call ASC
      jp EXIT
    
    COUT:
      mov ah,2
      int 21h
      ret
    
    STROUT:			
      mov ah,9 					
      mov dx,si
      int 21h
      ret
    
    ASC:
      mov byte [buffer+9],'$'
      lea si,[buffer+9]
      mov ax,cx
      mov bx,10 
    
    ASC_LOOP:
      mov dx,0
      div bx
      add dx,48
      dec si
      mov [si],dl
      cmp ax,0            
      jz STROUT
      jmp ASC_LOOP
    
    EXIT:
      mov ah,4ch
      int 21h
      ret
    
    buffer: db "          " ; 10 spaces.  no "resb" in my assembler.

    一个用于测试它的示例 PHP 脚本:

    <?php
    
    function getKey() {
    	return shell_exec("getkey.com");
    }
    
    print "Press [ESC] to exit.\n\n";
    
    $key = "";
    while (ord($key) != 27) {
    	$getch = explode(":",getKey());
    	$key = chr($getch[0]);
    	$scan = $getch[1];
    	if (ord($key) != 0) {
    		print $key;
    	} else {
    		print "SCAN:$scan\n";
    	}
    }
    
    ?>

    诚然,说到底,我意识到我可以用 C++ 做同样的事情。但这次我学到了更多关于 ASM 的知识。

    再次感谢各位!

    【讨论】:

      【解决方案4】:

      这是经过良好测试的打印数字代码

      .186
      .model SMALL
      .STACK 100h
      .data
          HelloMessage db 'Hello World', 13, 10, '$'
          SuperNumber dw 13565
      .code
      
      ; Writes word number from AX to output
      ; Usage
      ; .186
      ; ....
      ; mov ax, 13444
      ; call PRINT_NUMBER
      
      PRINT_NUMBER PROC NEAR  ; Outputs integer word number stored in AX registry. Requires CPU
          ; Save state of registers.
          PUSHA       ; Save all general purpose registers
          PUSH BP     ; We're going to change that.
      
          ; we need variables
      
          ; word number;      2 bytes
          ; byte digitsCount; 1 byte
      
          ; reserving space for variables on stack (3 bytes)
          mov bp, sp; ; bp := address of the top of a stack
          sub sp, 3*8 ; allocate 3 bytes on stack. Addresses of variables will be
                  ; number:   WORD PTR [rbp - 2*8]
                  ; digitsCount:  BYTE PTR [rbp - 3*8]
      
          ; Getting digits
          ; number = ax;
          ; digitsCount = 0;
          ; do
          ; {
          ;   push number%10;
          ;   digitsCount++;
          ;   number = number / 10;
          ; }
          ; while (number > 0)
          mov WORD PTR [bp - 2*8], ax ; number = ax;
          mov BYTE PTR [bp - 3*8], 0  ; digitsCount = 0;
      
          getDigits:          ; do
              mov ax, WORD PTR [bp - 2*8]; number/10: ax = number / 10, dx: number % 10
              ;cwd
              mov dx, 0
              mov bx, 10
              div bx
      
              push dx         ; push number%10
              mov WORD PTR[bp - 2*8], ax; number = number/10;
              inc byte PTR[bp - 3*8]  ; digitsCount++;
      
              cmp WORD PTR[bp - 2*8], 0; compare number and 0
              je getDigitsEnd     ; if number == 0 goto getDigitsEnd
              jmp getDigits       ; goto getDigits;
          getDigitsEnd:
      
          mov ah, 9
          mov dx, offset HelloMessage
          int 21h
      
      
          ;while (digitsCount > 0)
          ;{
          ;   pop digit into ax
          ;   print digit
          ;   digitsCount--;
          ;}
          printDigits:
              cmp BYTE PTR[bp - 3*8], 0; compare digits count and 0
              je printDigitsEnd   ; if digitsCount == 0 goto printDigitsEnd
      
              pop ax          ; pop digit into al
              add al, 30h     ; get character from digit into al
      
              mov ah, 0eh     ; wanna print digit!
              int 10h         ; BIOS, do it!
      
              dec BYTE PTR[bp - 3*8]  ; digitsCount--
      
              jmp printDigits     ; goto printDigits
          printDigitsEnd:
      
          ; Deallocate local variables back.
          mov sp, bp
      
          ; Restore state of registers in reverse order.
          POP BP
          POPA
      
          ; Exit from procedure.
          RET
      
      PRINT_NUMBER ENDP
      
      start:
          mov ax, @data
          mov ds, ax
      
          mov ah, 9
          mov dx, offset HelloMessage
          int 21h
      
          mov ax, 64454   
          call Print_Number
      
          mov ah, 4ch
          int 21h
      end start
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-12-20
        • 2017-04-27
        • 2016-12-25
        • 1970-01-01
        • 1970-01-01
        • 2021-02-15
        • 1970-01-01
        相关资源
        最近更新 更多