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

汇编实现实数转二进制时输入异常及崩溃问题求助

实数转二进制汇编代码的问题与修复

问题描述

基于原有整数转二进制的汇编代码修改后,实现实数转二进制时出现两个问题:

  • 输入带小数点的数值(如3.1)时触发访问违例错误,程序直接终止
  • 输入带逗号的数值(如3,1)时程序无响应

原代码

includelib legacy_stdio_definitions.lib
includelib ucrt.lib

EXTERN printf: PROC
EXTERN scanf: PROC
EXTERN exit: PROC

.data
unos BYTE "Unesite dva realna broja: ", 0              
ispis BYTE "Broj 1: %f (binarno): %s \nBroj 2: %f (binarno): %s \n", 0  
formatStr BYTE "%f", 0                                 
a REAL4 ?                                              
b REAL4 ?                                              
binBr1 BYTE 33 DUP(?)                                    
binBr2 BYTE 33 DUP(?)                                   

.code
public asmReal

konverBin proc
    push rbx                                            
    mov rbx, rdi                                        
    mov ecx, 32                                         

convertLoop:
    shl eax, 1                                          
    mov byte ptr [rbx], '0'                             
    adc byte ptr [rbx], 0                               
    add rbx, 1                                          
    loop convertLoop                                    

    mov byte ptr [rbx], 0                                       
    pop rbx                                             
    ret         
konverBin endp


asmReal proc
    lea     rcx, unos                                   
    call    printf                                      

input_a:
    lea     rcx, formatStr                              
    lea     rdx, a                                      
    call    scanf                                       
    cmp     eax, 1                                      
    jne     input_a                                    

input_b:
    lea     rcx, formatStr                              
    lea     rdx, b                                      
    call    scanf                                       
    cmp     eax, 1                                      
    jne     input_b                                     


    lea     rdi, binBr1
    mov     eax, dword ptr [a]
    call    konverBin


    lea     rdi, binBr2
    mov     eax, dword ptr [b]
    call    konverBin


    mov     rcx, OFFSET ispis
    movss   xmm0, dword ptr [a]                         
    movss   xmm1, dword ptr [b]                         
    lea     r8, binBr1
    lea     r9, binBr2
    call    printf

    xor     ecx, ecx                                    
    call    exit                                        

asmReal endp
END

错误信息

Exception thrown at 0x00007FFD529CB524 (ucrtbase.dll) in nekoeko.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

stdio.h相关代码片段:

#else
{
    return __stdio_common_vfprintf(_CRT_INTERNAL_LOCAL_PRINTF_OPTIONS, _Stream, _Format, _Locale, _ArgList);
}
#endif

问题根源分析

  1. printf参数传递完全错误
    格式串ispis的参数顺序为%f→%s→%f→%s,对应x64调用约定的参数位置应为:

    • 第一个%f:双精度浮点值放入xmm0
    • 第一个%s:字符串指针放入rdx
    • 第二个%f:双精度浮点值放入xmm1
    • 第二个%s:字符串指针放入r8
      原代码未设置rdx,反而将字符串指针放到了错误的寄存器,导致printf读取非法内存地址,触发访问违例。
  2. 单精度转双精度缺失
    原代码用movss直接加载单精度浮点数(REAL4)到XMM寄存器,但%f格式符要求双精度(REAL8),必须通过cvtss2sd指令完成类型转换。

  3. 输入逗号无响应
    系统区域设置差异导致:部分地区用逗号作为小数点分隔符,但scanf的%f默认只识别小数点(.),输入逗号时无法解析,会一直阻塞等待有效输入。


修复后的代码

includelib legacy_stdio_definitions.lib
includelib ucrt.lib

EXTERN printf: PROC
EXTERN scanf: PROC
EXTERN exit: PROC

.data
; 增加提示,明确要求使用小数点
unos BYTE "Unesite dva realna broja (koristite tacku kao decimalni znak): ", 0  
ispis BYTE "Broj 1: %f (binarno): %s", 0Ah, "Broj 2: %f (binarno): %s", 0Ah, 0  
formatStr BYTE "%f", 0                                 
a REAL4 ?                                              
b REAL4 ?                                              
binBr1 BYTE 33 DUP(?)                                    
binBr2 BYTE 33 DUP(?)                                   

.code
public asmReal

konverBin proc
    push rbx                                            
    mov rbx, rdi                                        
    mov ecx, 32                                         

convertLoop:
    shl eax, 1                                          
    mov byte ptr [rbx], '0'                             
    adc byte ptr [rbx], 0                               
    add rbx, 1                                          
    loop convertLoop                                    

    mov byte ptr [rbx], 0                                ; 字符串终止符
    pop rbx                                             
    ret         
konverBin endp


asmReal proc
    ; 打印提示信息
    lea     rcx, unos                                   
    call    printf                                      

    ; 输入第一个实数
input_a:
    lea     rcx, formatStr                              
    lea     rdx, a                                      
    call    scanf                                       
    cmp     eax, 1                                      
    jne     input_a                                    

    ; 输入第二个实数
input_b:
    lea     rcx, formatStr                              
    lea     rdx, b                                      
    call    scanf                                       
    cmp     eax, 1                                      
    jne     input_b                                     

    ; 转换第一个实数的IEEE754二进制表示
    lea     rdi, binBr1
    mov     eax, dword ptr [a]
    call    konverBin

    ; 转换第二个实数的IEEE754二进制表示
    lea     rdi, binBr2
    mov     eax, dword ptr [b]
    call    konverBin

    ; 严格按格式串顺序准备printf参数
    lea     rcx, ispis                ; 格式串(第一个参数)
    cvtss2sd xmm0, dword ptr [a]      ; 第一个%f:单转双精度放入xmm0
    lea     rdx, binBr1               ; 第一个%s:字符串指针放入rdx
    cvtss2sd xmm1, dword ptr [b]      ; 第二个%f:单转双精度放入xmm1
    lea     r8, binBr2                ; 第二个%s:字符串指针放入r8
    call    printf

    ; 退出程序
    xor     ecx, ecx                                    
    call    exit                                        

asmReal endp
END

额外说明

  • 原konverBin函数的逻辑是正确的:直接将REAL4的DWORD值按整数移位,得到的是IEEE754单精度浮点数的完整32位二进制表示。
  • 输入逗号的问题:修复方案是在提示信息中明确要求用户使用小数点;若需支持逗号分隔,需调用setlocale设置对应区域,会增加代码复杂度,简单场景下提示用户即可。

内容的提问来源于stack exchange,提问作者edodoe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 20:04:57