x86汇编:浮点数求和后无法打印,如何实现转字符串并输出?
如何正确打印汇编中的浮点数结果
问题根源
你的代码中,fistp dword [float3]确实将求和后的浮点数(3.14+1.59=4.73)转换为整数4,但后续直接用write系统调用输出float3的内存内容,这是在输出4的32位二进制表示(0x00000004)对应的ASCII字符,而非数字"4"的文本形式。write仅输出字节流,不会自动将数值转换为可阅读的ASCII字符串,因此出现乱码。
解决方案
要正确打印数值,必须先将数值转换为对应的ASCII字符串,再通过write输出。以下提供两种常见场景的实现:
场景1:打印整数部分(截断小数)
通过将浮点数转换为整数后,手动实现整数到ASCII字符串的转换:
section .data float1 dd 3.14 float2 dd 1.59 prompt db 'Result (integer part): ', 0 buffer db '00000', 0 ; 用于存储转换后的ASCII字符串 section .text global _start _start: ; 浮点数求和 movss xmm0, [float1] movss xmm1, [float2] addss xmm0, xmm1 ; 将浮点数转换为整数(截断小数),临时存在栈中 fistp dword [rsp-4] mov eax, [rsp-4] ; 整数转ASCII字符串,从buffer末尾开始填充 mov edi, buffer + 4 mov ecx, 10 ; 除数为10,用于逐位拆分数字 convert_loop: xor edx, edx div ecx ; eax = 商(剩余数字),edx = 余数(当前位) add dl, '0' ; 将余数转换为ASCII字符 mov [edi], dl dec edi test eax, eax ; 检查是否还有剩余数字 jnz convert_loop ; 打印提示信息 mov rax, 1 mov rdi, 1 mov rsi, prompt mov rdx, 23 ; "Result (integer part): "的长度 syscall ; 打印转换后的数字字符串 mov rax, 1 mov rdi, 1 mov rsi, edi + 1 ; 指向第一个非零数字的位置 mov rdx, buffer + 5 - (edi + 1) ; 计算字符串长度 syscall ; 打印换行符 mov rax, 1 mov rdi, 1 mov rsi, `\n` mov rdx, 1 syscall ; 退出程序 mov rax, 60 xor rdi, rdi syscall
场景2:打印带小数的浮点数(保留两位小数)
通过将浮点数放大100倍转换为整数,拆分出整数和小数部分后分别转换为ASCII,再拼接成带小数点的字符串:
section .data float1 dd 3.14 float2 dd 1.59 prompt db 'Result (with 2 decimals): ', 0 buffer db '00000.00', 0 ; 存储格式化后的字符串 hundred dd 100.0 section .text global _start _start: ; 浮点数求和 movss xmm0, [float1] movss xmm1, [float2] addss xmm0, xmm1 ; xmm0 = 4.73 ; 乘以100转换为整数(473),临时存在栈中 movss xmm1, [hundred] mulss xmm0, xmm1 fistp dword [rsp-4] mov eax, [rsp-4] ; eax = 473 ; 拆分整数部分(4)和小数部分(73) mov ecx, 100 xor edx, edx div ecx ; eax = 整数部分,edx = 小数部分 ; 转换整数部分到小数点前的位置 mov edi, buffer + 2 mov ecx, 10 int_convert: xor edx, edx div ecx add dl, '0' mov [edi], dl dec edi test eax, eax jnz int_convert ; 转换小数部分到小数点后的位置 mov eax, edx mov edi, buffer + 6 mov ecx, 10 dec_convert: xor edx, edx div ecx add dl, '0' mov [edi], dl dec edi test eax, eax jnz dec_convert ; 补零(确保小数部分为两位) fill_zero: cmp edi, buffer +4 jge skip_fill mov byte [edi], '0' dec edi jmp fill_zero skip_fill: ; 打印提示信息 mov rax, 1 mov rdi, 1 mov rsi, prompt mov rdx, 26 ; "Result (with 2 decimals): "的长度 syscall ; 跳过整数部分的前导零,准备打印 mov rsi, buffer skip_leading_zeros: cmp byte [rsi], '0' jne print_result inc rsi ; 如果全为零,保留一个零 cmp rsi, buffer +3 jne skip_leading_zeros dec rsi print_result: ; 打印格式化后的字符串 mov rax, 1 mov rdi, 1 mov rdx, buffer +7 - rsi ; 计算字符串长度 syscall ; 打印换行符 mov rax, 1 mov rdi, 1 mov rsi, `\n` mov rdx, 1 syscall ; 退出程序 mov rax, 60 xor rdi, rdi syscall
核心要点
write系统调用仅输出原始字节流,必须提供ASCII字符才能显示为可读数字。- 数值转ASCII的核心逻辑是通过除法拆分每一位数字,再加上
'0'的ASCII值得到对应字符。 - 处理浮点数小数部分时,可通过放大倍数将小数转换为整数,避免直接操作浮点数的复杂位运算。
内容的提问来源于stack exchange,提问作者Ömer Faruk Demirel
相关产品推荐
相关产品推荐

