为了将基数10中的任何数字转换为基数16,一个好的实现将是:
segment data use32 class=data
number dd 0
format_input db "%d", 0
format_output db "%x", 0
segment code use32 class=code
start:
push dword number
push dword format_input
call [scanf]
add esp, 4*2
push dword [number]
push dword format_output
call [printf]
add esp, 4*2
将数字从基数2转换为基数8是否有类似的实现?
答案 0 :(得分:1)
这是essentially a duplicate of this C/C++ question,因为您通过调用C库函数询问如何执行此操作。那没关系,没理由你不能在asm那样做。我决定不作为副本关闭,因为有足够的时间来说明如何正确地做到这一点只是为了评论它有点长。
C语法是一种更简单的方式来表达你需要粘合在一起的函数,所以我基本上只用C语言回答。如果你想在asm中做一个循环的任何步骤,那就去吧。将二进制字符串转换为整数非常简单,您只需一次移位一个数字。 (或使用SSE2 pmovmskb
)。
对base 8中的输出使用printf %o
转换;这是ISO C直接支持的。
Base 2 isn't, though。但strtoul
会根据您选择的基数转换字符串 - >无符号整数。唯一剩下的问题是将输入作为字符串读取。有很多方法可以做到这一点,但如果你想避免过度阅读和消费不属于base-2号码的字符,你可以scanf
使用%[]
仅接受字符0和1的转换。
所以你可以编写看起来像这样的asm:
// optionally this buffer could be static like your `number`, but there's no reason to do that.
char buf[65]; // reserve 65 bytes on the stack with sub esp, 80 (rounded up to keep stack 16B-aligned)
buf[0] = 0; // NULL terminate our stack buffer to avoid crashing in strtoul if scanf doesn't convert anything.
int success = scanf(" %64[01]", buf); // skip optional whitespace and store up to 64 bytes + null terminator into buf
// optional: check the conversion.
unsigned long num = strtoul(buf, NULL, 2); // parse as base 2, returning a binary integer
printf("%lo\n", num); // print as octal
// or %o if int and long are the same width in 32-bit asm
所有这些C语句都可以用一小段asm指令实现,而不是循环。如果你不确定如何,ask a compiler with gcc -O2 -S -masm=intel
。
请注意scanf
格式字符串中的长度限制,因此如果用户按住某个键并且您的程序读取1000个字节的1
,则不会有缓冲区溢出。
还要注意格式字符串中的前导空格,以跳过stdin
缓冲区中当前的任何空格。 (例如,前一行末尾的换行符,scanf
通常不会消耗)。 Conversions like %c
and %[
don't skip leading whitespace on their own
如果您希望使用尾随的非数字字符,请使用%64s
。 strtoul
将停在第一个非数字字符处。 (如果你传递非NULL char **
作为第二个arg,则存储指向该位置的指针。)