You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 22:54:51