【问题标题】:Converting a hex character within Assembly在程序集中转换十六进制字符
【发布时间】:2013-04-08 22:40:30
【问题描述】:

我目前正在为 8086 编写程序集。

我正在做的当前任务是将 4 个十六进制数字转换为其十进制表示。我试过遵循我的导师方法,但我在必须将十六进制数字乘以临时值的部分感到困惑,特别是当我被告知将其设为 0 时,每次乘以临时值总是会是 0 对吗?

我目前的代码如下,非常感谢任何帮助!

; ------------------------------------
; Name    : Gethex
; Function: converts a word (4 hex digits) into a numerical value
; Inputs  : Upto a word hex values input into the console
; Outputs : Return within DX the numerical conversion
; ------------------------------------

Gethex:
MOV BX,0H ;Temp value to 0
MOV CX,0H ;Counter set to 0
Gethexloop:
call Getch
push DX ; Putch requires DL, need to save current reg
MOV DL,AL
call Putch
pop DX ; restore DL reg
MOV BH,AH ;Use BH as temp storage as AH will be corrupted
cmp AL,30H ; ASCII 0
JL Gethexloop ; If less than 0 jump to the start as not an Alphabetical char
cmp AL,39H ; ASCII 9
JLE Nums ; If less or equal to 9 then it will be a number
cmp AL,46H
JLE Case ; Start the conversion procedure
Case:
SUB AL,10
jmp Convert
Nums:
SUB AL,30 ; Convert to normal number
Convert:
push AX ; Prepare to multiply
MOV AX,BX
mul BX
POP AX
ADD AX,BX
ADD DX,AX ; final value
ADD CX,1 ; Increase counter
cmp CX,3 ; if greater than 4 (0 being included so 3)
JG EndLoop
jmp Gethexloop
EndLoop:
ret ; return to calling statement

【问题讨论】:

  • 要求人们发现代码中的错误并不是特别有效。您应该使用调试器来隔离问题,方法是跟踪程序的进度,并将其与您期望发生的情况进行比较。一旦两者发生分歧,你就发现了你的问题。 (然后如果有必要,你应该构造一个minimal test-case。)

标签: assembly x86 x86-16 hex


【解决方案1】:

只是一些观察...首先,一个数字是一个数字是一个数字。 “十六进制”和“十进制”(以及“二进制”和“八进制”)是表示数字的方式 - 它是相同的数字。一步将“十六进制表示”转换为“十进制表示”会很困难(但可能......我猜)。您要做的是将十六进制表示形式转换为数字...然后可能将数字转换为其十进制表示形式以便我们可以打印它。

你的“temp”变量,我喜欢称之为“result so far”,一开始就设置为零,但它不会为每个字符/数字重置为零!一般程序是将“到目前为止的结果”设置为零,然后对于遇到的每个有效数字,将“迄今为止的结果”乘以基数 - 十进制为 10,十六进制为 16 - 然后添加新数字......当然,从字符转换为数字。重复直到你的字符用完

mul 是一个非常好的指令,但它有“隐藏”的操作数(在我们的例子中是axdx)。乘以 10,我们没有太多选择,但是乘以 16 可以通过shl reg, 4 完成,而且“副作用”更少。如果您真的使用 8086,则只有 1cl 是有效的操作数。仅在 80186 中引入了除一个之外的“立即数”(80286 出于实用目的 - 80186 很少见)。您几乎可以肯定使用它,但也许您不是“应该”。我怀疑您“应该”为此使用mul - 无论如何都更容易检查溢出(如果您希望这样做 - 将输入限制为 4 个字符应该避免溢出)。

我看不出您的 mov bh, ah 行的目的 - ah 在这一点上是否包含任何“有趣”的内容?

几乎所有汇编程序都会接受cmp al, '0' - 与cmp al, 48cmp al, 30h 相同的代码。我发现前者使指令的目的更清晰,但实际上并不重要。

jljg 用于有符号数 - 0FFh 将被解释为 -1,并将比较为“小于”零。在这段代码中,您不会遇到任何“大到足以成为负数”的数字,所以这无关紧要,但 jbja 用于无符号数字(0FFh 被解释为 255)并且可能是“更正确”。这只是一个挑剔的选择,但您不妨了解其中的区别 - 有时它确实很重要。

    cmp AL,46H
    JLE Case ; Start the conversion procedure
Case:
    SUB AL,10

再一次,我更喜欢cmp al, 'F' - 但它产生相同的代码。如果al 不小于或等于(同样jbe 对无符号是正确的),那么无论如何你都会遇到Case:。我怀疑这是否是你想要的!而且我不明白你为什么要减去 10。如果你要减去“0”,我会认为是 37h,或者只是 7。

讨厌的用户输入 'a'..'f' 和输入 'A'..'F' 的可能性一样大。为了做一个合适的“toupper”,我们要确保角色有一个“case”。在这里,无论如何,我们将拒绝除 'A'..'F' 以外的任何内容,所以如果我们通过强制没有“大写”的字符来产生一些垃圾也没关系。确保您首先处理了十进制数字! and al, 0DFh ; force to uppercase。您可能想要也可能不想这样做 - 可能只是强制用户使用 shift 键。 :)

用户输入以回车结束 - 13 或 0Dh - (我记得... Linux 使用换行 - 10 或 0Ah - 但我认为 dos 是 13)。您可能想先检查一下 - 在十进制或十六进制数字之前。我认为您当前的设置将等待用户输入 4 个字符,即使他们点击了“输入”。可能不是预期的行为...

是的,获取一个调试器并学习如何使用它。一步一步地看到正在发生的事情会对你有很大帮助。以前很喜欢David Lindauer的GRDB……(像DEBUG只有更亮)……

【讨论】:

  • 嗨弗兰克,谢谢你的帮助,我想我现在已经可以工作了,调试结果是正确的 :) 感谢你友好的语气 :)
  • 对了,有什么推荐的书籍或者教程吗?
猜你喜欢
  • 1970-01-01
  • 2018-01-31
  • 2015-05-28
  • 2017-07-30
  • 1970-01-01
  • 2018-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多