无法连续两次从变量输出协处理器浮点数 [英] Can't output coprocessor float from variable two times in a row

查看:47
本文介绍了无法连续两次从变量输出协处理器浮点数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下午好!在此示例中,我仅用逗号添加两个数字,将变量保存在 tbyte 中,并在屏幕上连续两次显示相同的变量,但这是我第一次获得 11.1 ,并且第二次 4.667261E-062 .为什么会这样?

Good afternoon! In this example, I simply add two numbers with a comma, save the variable in tbyte and display the same variable two times in a row on the screen, but the first time I get 11.1, as it should be, and the second time 4.667261E-062. Why is this happening?

还有一个问题,是否可以在 tbyte 中以某种方式按数组类型保存和访问数字?例如,将数字存储在 dd 中,我只能以4的增量进行保存和读取,例如,结果[0] 结果[4] 等.是否可以将其与 tbyte 一起使用,如何使用?如果我理解正确-应该是 10 的一个步骤.

And one more question, is it possible in tbyte to somehow save and access numbers by array type? for example, storing numbers in dd, I just could save and read them in increments of 4, for example, result [0], result [4], etc. Is it possible to use the same with tbyte and how? If I understand right - it should be a step of 10.

.386
.model flat,stdcall
option casemap:none

include \masm32\include\masm32rt.inc

.data
titletext db  'Title',0
frmt db 'Result1 = %.7G',10
     db 'Result2 = %.7G',0
buff db 1024 dup (?)
result tbyte ?
num1 qword 5.5
num2 qword 5.6

.code
start:
    finit
    fld qword ptr [num1]
    fld qword ptr [num2]
    fadd
    fstp qword ptr [result]

    invoke crt_sprintf,addr buff,addr frmt, result, result
    invoke MessageBox,0,addr buff,addr titletext,MB_OK
    invoke ExitProcess,0
end start

推荐答案

为什么要对一个tbyte( long double)?

Why are you doing a fstp qword (double) into a tbyte (long double)?

哦,这可能是您的错误.大概 invoke 宏为每个 result 宏args压入12个字节.(由于将10字节的 tbyte 填充到4字节的堆栈插槽的倍数中,因此为12).

Oh, that's probably your bug. Presumably the invoke macro pushes 12 bytes for each of the result macro args. (Because a 10-byte tbyte padded to a multiple of 4-byte stack slots is 12).

但是您的格式字符串仅告诉sprintf查找8字节宽的 double args.由于仅将一个qword double 存储到 result 的低8个字节中,因此 crt_sprintf 可以正确读取第一个可变参数arg作为 double.(x86是little-endian,因此低8个字节位于sprintf正在查看的堆栈地址处.)

But your format string only tells sprintf to look for double args, which are 8 bytes wide. Since you only stored a qword double to the low 8 bytes of result, crt_sprintf can correctly read the first variadic arg as a double. (x86 is little-endian so the low 8 bytes are at the stack address sprintf is looking at.)

但是第二个%G 转换将在上一个arg结束后立即寻找另一个 double .根据格式字符串,哪个应该晚8个字节.但是您的 invoke 实际推送的内容与此不匹配.因此,第二个%G 读取8个字节,与两个12字节的请求重叠.

But the 2nd %G conversion will be looking for another double right after the end of the previous arg. Which according to the format string should be 8 bytes later. But what your invoke actually pushed didn't match that. So the 2nd %G reads 8 bytes that overlap the two 12-byte pushes.

它的高4个字节(包括指数和符号位)可能为 0 ,仅在尾数的低31位中为非零,这给您一个非常小的非正常数.您可以使用调试器将内存作为 double 进行检查,并查看其是否代表sprintf read的值.

It's probably 0 in the upper 4 bytes (including exponent and sign bit), and non-zero only in the low 31 bits of the mantissa, giving you a very small subnormal number. You can use a debugger to examine memory as a double and see that it represents the value sprintf read.

如果该库中的 long double 是10字节x87类型,请使用%LG 并使用 fstptbyte .

If long double in that C library is the 10 byte x87 type, use %LG and use fstp tbyte.

如果 sizeof(long double)只有8,则它与 double 相同,并且您无法使用该C库打印x87个tbyte值.(除非它具有一些非标准扩展名.)在这种情况下,您只需将 result 更改为 qword ,以匹配您正在做的商店

If sizeof(long double) is only 8, then it's the same as double and you can't printf x87 tbyte values with that C library. (Unless it has some non-standard extension for it.) In that case You just change result to also be a qword, matching the store you're doing.

此外,您没有平衡x87堆栈;使用 faddp ,因此在 fstp .(如果汇编器需要操作数,请使用 faddp st(1) st1 ,但是它喜欢拼写x87寄存器名称.)

Also, you didn't balance the x87 stack; use faddp so it's empty after the fstp. (If your assembler requires an operand, use faddp st(1) or st1, however it likes to spell x87 register names.)

从技术上讲,您通过对x87堆栈进行非空函数调用而违反了调用约定,但显然crt_sprintf并未使用全部8个 st0..7 ,因此它不会通过溢出x87堆栈获得NaN.

You're technically violating the calling convention by making a function call with the x87 stack non-empty, but apparently crt_sprintf doesn't use all 8 of st0..7 so it doesn't get a NaN from overflowing the x87 stack.

这篇关于无法连续两次从变量输出协处理器浮点数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆