无法连续两次从变量输出协处理器浮点数 [英] Can't output coprocessor float from variable two times in a row
问题描述
下午好!在此示例中,我仅用逗号添加两个数字,将变量保存在 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屋!