【问题标题】:Using EMU8086, is there a direct way to print a variable's hex value?使用 EMU8086,是否有直接打印变量十六进制值的方法?
【发布时间】:2015-08-19 17:07:44
【问题描述】:

我在 Windows 7 HP x64、Intel i3-2330m 电脑上使用 EMU8086。

我花了大约两周的时间研究和修改这个汇编语言程序,以便打印用户输入的整数的十六进制值。我没有发现直接从内存位置打印值。如有必要,我可以编写代码将字符串转换为十六进制。但是,我试图避免额外的代码行来执行此操作。 (我认为这叫做优化。)

我的研究让我找到了comment on this site by Corbin,上面写着:

非常不愉快。您必须确定小数的值 字符串(“100”),然后创建一个与十六进制值相同的新字符串 (“0x64”)。它与您用于进行转换的算法相同 你的脑袋;它只是有点复杂,因为你必须处理 最重要的是 ASCII 编码。

这些都没有引导我以我希望执行任务的方式。

我已逐步编写和测试代码,收到了预期的结果。通过观察变量和查看 CX 寄存器,我可以确认它们的值就是我要打印的值。

我在这里包含我的代码。它可能很丑陋,并且肯定被过度评论了。评论是为了帮助我学习/记住我在进步时所做的事情。

 ; program name: convert_decimal_to_hex
 ; by W K
 ; August, 2015
 ; This program accepts an integer between 1 and 10000 and
 ; prints the hexadecimal value to the console
 ;
 ;
 #MAKE_COM# ;instruct compiler to make COM file
 include emu8086.inc    ;use include file for macros
 ORG 100h   ;directive for COM program, set offset to 100h
 ;
 MOV DX, offset msg1    ;moves value of msg1 to the data register
 ;                       
 MOV AH, 9  ;moves the value 9 to the high accumulator register
            ;to be used with the interrupt
 INT 21h    ;invokes interrupt to print string to DOS window
 ;
 MOV DX,13  ;these lines
  MOV AH,2  ;create a
  INT 21h   ;newline
  MOV DX,10 ;and
  MOV AH,2  ;move the cursor
  INT 21h   ;to the newline
 ;
 CALL SCAN_NUM  ;calls macro to scan numeric keyboard input
                ;error catching is included in macro
                ;number is stored in CX 
  MOV DX,13 ;these lines
  MOV AH,2  ;create a
  INT 21h   ;newline
  MOV DX,10 ;and
  MOV AH,2  ;move the cursor
  INT 21h   ;to the newline
 ;  
 MOV DX, offset msg2    ;moves value of msg2 to the data register
 MOV AX, CX ;copies scanned number to AX to be printed
            ;as part of message
 ;MOV AH, 9  ;moves the value 9 to the high accumulator register
             ;to be used with the interrupt
 ;INT 21h    ;invokes interrupt to print string to DOS window 


 CALL PRINT_NUM_UNS  ;prints hexadecimal value at end of msg2
 MOV CONVERTEDNUMBER, CX
 ;                       
 MOV AH, 9  ;moves the value 9 to the high accumulator register
            ;to be used with the interrupt
 INT 21h    ;invokes interrupt to print string to DOS window
 ;
 MOV AX, 0  ;wait for any key
 INT 16h    ;prevents window from closing immediately
 ;
 msg1 db "Type an integer between 1 and 10000, and press enter. $"    
    ;declare string variable 
 msg2 db " in hexadecimal is: $" 
 ;
 DEFINE_SCAN_NUM    ;defines macro from include file
                    ;gets multidigit signed number from keyboard
 DEFINE_PRINT_NUM_UNS   ;defines macro from include file
                        ;prints unsigned number in AX
 ;                                                   
 CONVERTEDNUMBER DW 0   ;declare variable
 ;
 RET    ;return to operating system
 END    ;directive to stop compiler

有没有程序可以直接打印变量值或CX寄存器值而无需编写代码行来转换用户输入的字符串值?对文章、代码示例或其他有用建议的任何引用将不胜感激。

【问题讨论】:

  • 没有标准的 MS-DOS 或 BIOS 服务可以将存储在字符串中的十进制数转换为存储在字符串中的十六进制数。 EMU8086 可能对此有某种扩展,但我对此表示怀疑。如果您想要这种功能,我建议您学习更高级的语言,例如 C 或 Python。如果您的示例代码不起作用,您需要发布另一个问题,其中包含重现问题所需的所有代码,然后任何人都可以帮助您找到并修复错误。

标签: assembly x86


【解决方案1】:

DOS 只为您提供将字符 写入标准输出的中断(INT 21H / AH=2 用于单个字符,INT 21H / AH=9 用于以$ 结尾的字符串)。

因此,您必须首先将要打印的任何数字转换为字符串,无论您希望在何种基础上显示该数字。幸运的是,这很容易做到。下面是一个如何打印 32 位十六进制数字的示例(我将把它作为练习留给您去除前导零):

; Input:
; EAX = value to print
;
print_hex:
    mov cx,8        ; print 8 hex digits (= 32 bits)
    .print_digit:
        rol eax,4   ; move the currently left-most digit into the least significant 4 bits
        mov dl,al
        and dl,0xF  ; isolate the hex digit we want to print
        add dl,'0'  ; and convert it into a character..
        cmp dl,'9'  ; ...
        jbe .ok     ; ...
        add dl,7    ; ... (for 'A'..'F')
    .ok:            ; ...
        push eax    ; save EAX on the stack temporarily
        mov ah,2    ; INT 21H / AH=2: write character to stdout
        int 0x21
        pop eax     ; restore EAX
        loop .print_digit
        ret

以 10 或 2 为底的打印数字并没有太大的不同。只是当我们处理为 2 的幂的基数(如 16 或 2)时,我们可以使用移位(或在我的代码中旋转)和 AND,而不是除法和余数。

【讨论】:

  • 因为这个练习我只使用汇编语言,而且我使用的是 EMU8086(16 位仿真器),所以需要一点点努力才能做到这一点。这对我来说没有问题,因为我将获得学习经验。我以为我在直接打印值的过程中忽略了一些东西。提供的代码将有助于编写适当的 16 位代码。
  • 我的答案中的代码是有效的 16 位代码。虽然它可能需要 80286 或 80386 才能运行,因为使用了EAX。简单的解决方法是将所有出现的 EAX 更改为 AX(尽管这会限制您打印 16 位值)。
  • 最好在整个函数周围推送/弹出ebx,而不是循环内的eax 的push/pop
  • 你能重复使用这段代码来打印多个变量吗?我试图打印 var1 并在打印 var2 之后,但我在那里遇到了一些问题@Michael
  • @lLauriix 我不明白为什么那行不通。但是如果你想在两个数字之间插入一些空格,那么你必须自己这样做,因为这个函数不会这样做。
猜你喜欢
  • 1970-01-01
  • 2012-10-09
  • 1970-01-01
  • 2014-04-27
  • 1970-01-01
  • 1970-01-01
  • 2013-05-10
  • 1970-01-01
  • 2013-03-31
相关资源
最近更新 更多