这是家庭作业,我需要转换64位(20个字符的用户输入)。十进制到十六进制
我的第一步是将char转换为十进制,因此我需要将用户输入的ASCII
转换为十进制。
如何移动和获取用户输入的字符串的最后一个值组装中?
假设我要一个数字,为了简单起见,用户输入了121
,我知道这是ASCII 31,32,31
字符,我需要先将其转换为十进制,所以我想取最低有效位,即从最右边到最高有效位的数字(从右到左)。
这是我的代码:
initialize:
xor rax, rax ; initializes rax
mov rcx, 0 ; initialize rcx
mov rbx, 0 ; clear register to store result
mov rdx, 1 ; initliaze rdx to base 10 (10^0)
convertInputToDigits:
mov rcx, [count] ; initialize count
mov rsi, buf ; point to start of buffer
add rsi, [count] ; move to end of user input, this part may be wrong
mov rbx, [rsi-1] ; move the first rightmost number in rbx
sub rbx, '0' ; subtract hex value 30 for each character
; to get decimal value 0-9
mov rax, [rbx] ; move the result in rax
mul rdx ; multiply result, power of 10(rax*rdx)
add rbx, rax ; stores the total in rbx
dec rsi ; decrement up until first character
cmp rsi, 0 ; check if we are at the end of input/converted all input to decimal
je convertToHex ; if so jump to conversion
mov ax, [rdx] ; move value of rdx to ax
imul ax, 10 ; updates to the next power by 10*1 (10^1, 10^2)
jmp convertInputToDigits ; if not, loop again
我做错了什么?该如何解决?
谢谢!
第页。S.output: 6296.
不知道它是怎么得到的,但肯定不是我需要转换的十进制121。
我想说的太多了,无法放在评论中。但既然我不打算为你做家庭作业,让我们看看我是否能解释这些问题,然后你就能解决它们。
因此,从顶部开始:
initialize:
xor rax, rax ; initializes rax
这个"初始化"对rax有什么作用?你知道吗?如果这是课堂,我会等你回答,但我假设你已经知道它将rax设置为零。考虑到这一点,这条线对rcx有什么作用?
mov rcx, 0 ; initialize rcx
很明显,它将其设置为零。那么…为什么要用两种不同的方法将寄存器设置为零呢?读起来有点困惑。此外,一个可能比另一个更有效率,那么为什么不总是使用最高效的呢?哪一个最有效?看看这个。
继续:
mov rbx, 0 ; clear register to store result
mov rdx, 1 ; initliaze rdx to base 10 (10^0)
我们将忽略拼写错误。。。
convertInputToDigits:
mov rcx, [count] ; initialize count
这不会"初始化"计数。它将count指定的内存中的当前值读取到rcx中。希望计数是8字节长。这就是rcx的大小,也就是mov要读取的字节数。你没有显示count被分配了一个值,但我希望你这样做。否则rcx将只包含垃圾。
mov rsi, buf ; point to start of buffer
add rsi, [count] ; move to end of user input, this part may be wrong
我不清楚你为什么在循环中有这些线。当您到达循环的底部并跳回convertInputToDigits
时,您不想将rsi重置为buf并再次添加"count"。您想设置rsi一次,然后向后走计数次。
实际上,您也不希望/不需要多次读取count。
mov rbx, [rsi-1] ; move the first rightmost number in rbx
由于rbx是8个字节长,因此它将读取[rsi-1]处的8个字节。正如我们所讨论的,这可能不是你想要的。
sub rbx, '0' ; subtract hex value 30 for each character
; to get decimal value 0-9
mov rax, [rbx] ; move the result in rax
你想把rbx复制成rax吗?因为这不是mov
的作用。相反,它将尝试从rbx中的内容指定的内存位置进行读取。但是存储在rbx中的不是内存位置(应该是数字1,对吧?)。所以我预计这会因访问违规而崩溃。
如果你真的想把rbx复制到rax中,那就是mov rax, rbx
。
或者,为什么要将值读取到rbx中并复制它?为什么不首先使用rax呢?看看你的评论,你不打算用RBX做其他事情吗?
mul rdx ; multiply result, power of 10(rax*rdx)
好的,让我们来谈谈它的作用。简而言之,就是RDX:RAX=RAX*RDX。虽然您只指定RDX,但其余部分是隐含的。现在,"RDX:RAX"是什么意思?好吧,如果RAX和RDX中的值真的很大,那么将它们相乘会得到一个太大的结果,无法放入单个寄存器。因此mul
使用2个寄存器来保存结果。RDX将是较高的比特,而RAX将保持较低的比特。
对于121,永远不会有足够大的结果来填充多个寄存器,所以RDX最终总是为零。这将是下面的一个问题。
add rbx, rax ; stores the total in rbx
存储总数是一件好事,这正是你想要做的。但你已经在使用rbx做其他事情了。因此,当您第二次通过循环时,rbx将不会得到第一次循环的结果。
dec rsi ; decrement up until first character
cmp rsi, 0 ; check if we are at the end of input/converted all input to decimal
je convertToHex ; if so jump to conversion
让我们花点时间讨论一下cmp/je的作用。简而言之,cmp进行比较,然后设置一些其他指令(如je)可以使用的标志。然后je查看cmp设置的标志,并根据需要跳转。但事实证明,cmp并不是唯一设置标志的指令。dec
也是如此。因此,您可以通过使用dec设置的标志来查看rsi是否为零,而无需执行额外的cmp。
(顺便说一句,如果你确实需要在没有做dec
或其他事情的情况下检查零,test rsi,rsi
的效率略高于cmp rsi,0
)。
但这里更重要的问题是rsi不会为零。使用我在评论中给出的示例:
如果rsi为0x100,则"121"的3个字节将分别为0x100、0x101和0x102。
因此,如果我们从0x103开始(通常地址会大得多),那么我们对三个数字中的每一个都递减一次,我们不是在寻找零。那么,我们能减少什么,目前的值是3<咳嗽>rcx<咳嗽>
mov ax, [rdx] ; move value of rdx to ax
还记得我说过把rdx设置为零会有问题吗?好吧,就是这样。如果rdx为零,那么您正在尝试读取内存位置[0]。这将是一个访问违规。由于rdx将在每个循环中为零,也许您应该选择一个不同的寄存器来存储您的功率。
imul ax, 10 ; updates to the next power by 10*1 (10^1, 10^2)
这种形式的刺激将有效地达到ax=ax*10。但是ax是你想要存储结果的地方吗?
jmp convertInputToDigits ; if not, loop again
所以,这似乎有很多问题。是的,确实是这样。但你似乎正确地理解了你想做什么,即使你对如何做有点模糊。
希望这能帮助你更好地了解正在发生的事情,并为你指明正确的方向。