如何正确使用FDIV指令?16位MASM混合C++求均值出错排查
问题分析与解决方案
你的问题主要出在汇编代码的两个关键错误上,再加上C++代码里的一个内存分配问题,下面逐一拆解:
1. 汇编中的核心错误
错误点一:覆盖栈帧指针BP,丢失参数上下文
你在代码中用mov bp, ax把数组地址存入BP,直接覆盖了原本用来指向栈帧的BP指针——BP的核心作用就是维护函数栈帧、访问参数和局部变量,覆盖它之后,后续再也无法正确获取size参数。虽然你之后执行了mov bp, sp,但此时原始栈帧的上下文已经丢失,[bp+6]取到的只是栈内的随机数据,根本不是传入的size值。
错误点二:误用整数作为浮点数除法的操作数
size是int类型,但你直接用fdiv指令对它做浮点除法。fdiv会把操作数当作32位浮点数解析,而int类型的5(0x00000005)作为浮点数是一个极小的非规格化值(约1.4e-44),用求和结果5.0除以这个极小值,自然会得到一个极大的错误结果(类似你看到的6.39516e+33)。正确的做法是用fidiv指令,它会自动将整数转换为浮点数后再执行除法。
2. C++代码中的野指针问题
你的C++代码里float *array;只是声明了指针,但没有分配内存,属于野指针。直接用cin>> *(array+i)写入会导致未定义行为,你说求和结果“正确”只是巧合,实际会破坏内存。
修正后的代码
修正后的C++代码
#include <iostream.h> #include <stdlib.h> #include <math.h> extern "C" float f1(float *arr, int); int main() { int size = 5; // 分配内存,避免野指针 float *array = new float[size]; cout << "Give your numbers:" << endl; for(int i = 0; i < size; i++) { cin >> *(array + i); } cout << "\nAverage = " << f1(array, size); // 释放内存 delete[] array; return 0; }
修正后的汇编代码
.model SMALL, C .data .code PUBLIC f1 f1 PROC NEAR push BP mov BP, SP ; 用SI存储数组地址,保留BP维护栈帧 mov SI, [BP+4] ; 获取arr参数地址 mov CX, [BP+6] ; 获取size参数 fld dword ptr [SI] ; 加载第一个元素到st(0) dec CX ; 循环次数为size-1次 jz SkipLoop ; 处理size=1的边界情况 Loop1: add SI, 4 ; 移动到下一个float元素(4字节) fld dword ptr [SI] ; 加载当前元素到st(0),原st(0)移到st(1) fadd ; st(1) += st(0),结果存回st(0) loop Loop1 SkipLoop: ; 使用fidiv自动将整数size转为浮点数后除法 fidiv dword ptr [BP+6] pop BP ret f1 ENDP .stack db 100(?) END
修正说明
- 寄存器合理使用:用SI寄存器存储数组地址,保留BP作为栈帧指针,确保能稳定访问函数参数。
- 正确的除法指令:
fidiv会自动完成整数到浮点数的转换,避免了类型解析错误。 - 边界处理:增加
jz SkipLoop判断,避免当size=1时进入循环导致错误。 - 内存安全修复:C++代码中用
new分配数组内存,并用delete[]释放,彻底解决野指针问题。
内容的提问来源于stack exchange,提问作者KApacze
相关产品推荐
相关产品推荐

