-1

我目前正在为 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
4

1 回答 1

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

jl并且jg用于有符号数 -0FFh将被解释为 -1,并将比较为“小于”零。在此代码中,您不会遇到任何“大到足以为负”的数字,所以这无关紧要,但jbandja用于无符号数字(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只是更亮)...

于 2013-04-09T07:20:31.650 回答