在vc中,如果你将一个浮点数强制转换成一个整数,比如int i = (int)f;
那么简单的一句话,就有可能被编译器转换为一个函数调用,就是_ftol2,参数为一个浮点数,开始函数调用前,该参数已经被压入浮点寄存器堆栈st(0)中,取整规则为去尾,即偏向0。
浮点寄存器堆栈一共从st(0)到st(7),可以看做一个循环队列。堆栈顶端为st(0),st(0)简称st
_ftol2:
0040142C 55 push ebp
0040142D 8B EC mov ebp,esp
0040142F 83 EC 20 sub esp,20h //堆栈上空出20h个字节,用于存储临时变量
00401432 83 E4 F0 and esp,0FFFFFFF0h //将esp对齐到16字节
00401435 D9 C0 fld st(0) //压入st(0),原先的st(0)变为st(1),这样st(1) == st(0)
00401437 D9 54 24 18 fst dword ptr [esp+18h] //将st(0)转换为单精度(dword) 保存倒[esp + 18h]位置
0040143B DF 7C 24 10 fistp qword ptr [esp+10h] //将st(0)取整保存到[esp+10h]位置,这个结果是64位的(qword),结果偏0还是远离0应该取决于协处理器msw。同时弹出st(0),原先的st(1)变为st(0)
0040143F DF 6C 24 10 fild qword ptr [esp+10h] //将刚才取整的结果load到st(0)。现在st(1)是原值,st(0)是取整后的值
00401443 8B 54 24 18 mov edx,dword ptr [esp+18h] //取原值单精度版到edx
00401447 8B 44 24 10 mov eax,dword ptr [esp+10h] //取64位取整结果的低32位
0040144B 85 C0 test eax,eax
0040144D 74 3C je integer_QnaN_or_zero (0040148B) //如果eax位0,则该浮点数可能是0或者NAN
arg_is_not_integer_QnaN:
0040144F DE E9 fsubp st(1),st //原值减去取整后的结果,结果在st(0)中。取整结果如果偏0, 原值为正结果得正,原值为负结果得负; 取整结果如果远离0, 原值为正结果得负,原值为负结果得正
00401451 85 D2 test edx,edx //测试原浮点数的单精度格式
00401453 79 1E jns positive (00401473) //如果原值是非负数则跳转,以下是负数的处理方法
00401455 D9 1C 24 fstp dword ptr [esp] //将减法结果保存到[esp]位置,弹出栈顶元素,st(0)变为原值
00401458 8B 0C 24 mov ecx,dword ptr [esp]
0040145B 81 F1 00 00 00 80 xor ecx,80000000h //减法结果最高位取反,其余位不变
00401461 81 C1 FF FF FF 7F add ecx,7FFFFFFFh //如果减法结果为正,则最高为取反后为1,再加7FFFFFFFh必定CF=1,即远离0;如果减法结果为0或者负数,则CF=0,即偏向0
00401467 83 D0 00 adc eax,0 //对于负浮点数,取整结果远离0(CF=1)就是多减了1,需要加1,让结果偏0;取整结果如果偏向0(CF=0),结果eax加上CF和0,值仍然不变
0040146A 8B 54 24 14 mov edx,dword ptr [esp+14h]
0040146E 83 D2 00 adc edx,0
00401471 EB 2C jmp localexit (0040149F)
positive:
00401473 D9 1C 24 fstp dword ptr [esp] //注释同上
00401476 8B 0C 24 mov ecx,dword ptr [esp]
00401479 81 C1 FF FF FF 7F add ecx,7FFFFFFFh
0040147F 83 D8 00 sbb eax,0 //对于正浮点数,取整远离0(CF=1)就是多加了1,需要减1,让结果偏0;取整结果如果偏向0(CF=0),结果减去CF和0,值仍然不变
00401482 8B 54 24 14 mov edx,dword ptr [esp+14h]
00401486 83 DA 00 sbb edx,0
00401489 EB 14 jmp localexit (0040149F)
integer_QnaN_or_zero: //对于0或者NAN
0040148B 8B 54 24 14 mov edx,dword ptr [esp+14h] //取64位取整结果的高32位
0040148F F7 C2 FF FF FF 7F test edx,7FFFFFFFh //测试高字的低31位,
00401495 75 B8 jne arg_is_not_integer_QnaN (0040144F)
00401497 D9 5C 24 18 fstp dword ptr [esp+18h]
0040149B D9 5C 24 18 fstp dword ptr [esp+18h]
localexit:
0040149F C9 leave
004014A0 C3 ret //结果在eax中