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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:51:38