FASM中浮点运算返回0,内联汇编可正常运行
问题分析与解决方案
嘿,我一眼就瞅出问题所在了——这是浮点数类型不匹配导致的!
核心问题
你用FASM写的代码里,fv和fv2是32位单精度浮点数(dd 5.0f,对应C里的float),但调用printf时用的%f格式符,默认期望接收的是64位双精度浮点数(对应C里的double)。
为啥VC内联汇编能正常跑?因为C编译器会帮你做一件事:当把float类型传给printf这种可变参数函数时,会自动触发默认参数提升,把float隐式转换成double再传递。但纯FASM代码里没人帮你干这个,你直接把32位的float压栈,printf按64位double去解析,自然读出来的是错误数据,表现为输出0.0000。
两种修复方案
方案1:直接使用双精度浮点数(适配printf的%f)
把数据定义改成双精度(用dq指令,对应C的double),同时用SSE的双精度指令操作:
section .data fmt db 'fv = %f',0ah,0 fv dq 5.0 ; 双精度浮点数(8字节) fv2 dq 2.0 section .text _main: enter 0,0 ; 执行 fv *= fv2 movsd xmm0,[fv] ; 加载双精度值到xmm0 movsd xmm1,[fv2] mulsd xmm0,xmm1 ; 双精度乘法 movsd [fv],xmm0 ; 传递参数给printf(cdecl调用,参数从右往左压栈) sub esp,8 ; 为8字节的double分配栈空间 movsd [esp],xmm0 ; 把结果写入栈 push fmt ; 压入格式字符串地址 call _printf add esp,12 ; 清理栈(8+4=12字节) leave ret
方案2:保持单精度,手动转换为双精度再传递
如果想继续用32位float,就在传递给printf前用SSE指令把单精度转成双精度:
section .data fmt db 'fv = %f',0ah,0 fv dd 5.0f fv2 dd 2.0f section .text _main: enter 0,0 ; 执行 fv *= fv2 movss xmm0,[fv] movss xmm1,[fv2] mulss xmm0,xmm1 movss [fv],xmm0 ; 把单精度float转成双精度double cvtss2sd xmm0,xmm0 ; xmm0现在存储双精度结果 ; 传递参数给printf sub esp,8 movsd [esp],xmm0 push fmt call _printf add esp,12 leave ret
额外注意
Windows平台下调用C标准库函数前,需要保证栈对齐到16字节边界(你的代码用enter 0,0可能刚好满足,但复杂场景下要注意手动调整),不过这次的核心问题还是类型不匹配,修复后就能正常输出10.0000啦!
内容的提问来源于stack exchange,提问作者C. Dunn
相关产品推荐
相关产品推荐

