Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Visual c++ 在Microsoft Visual Studio中读取并显示程序集中的浮点数或双倍数_Visual C++_Assembly_Floating Point_X86_Masm - Fatal编程技术网

Visual c++ 在Microsoft Visual Studio中读取并显示程序集中的浮点数或双倍数

Visual c++ 在Microsoft Visual Studio中读取并显示程序集中的浮点数或双倍数,visual-c++,assembly,floating-point,x86,masm,Visual C++,Assembly,Floating Point,X86,Masm,我正在使用Microsoft Visual Studio 2015学习内联汇编编程。我读过很多关于stackoverflow的帖子,包括最相关的一篇,但是在我尝试了这些方法之后,结果仍然是0.0000。我首先使用float并将值存储到fpu,但reuslt是相同的,并尝试将值传递给eax,但仍然没有帮助 这是我的密码: #include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { char input1[] = "Enter n

我正在使用Microsoft Visual Studio 2015学习内联汇编编程。我读过很多关于stackoverflow的帖子,包括最相关的一篇,但是在我尝试了这些方法之后,结果仍然是0.0000。我首先使用float并将值存储到fpu,但reuslt是相同的,并尝试将值传递给eax,但仍然没有帮助

这是我的密码:

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])
{
    char input1[] = "Enter number: \n";
    char input_format[] = "%lf";
    double afloat;
    char output[] = "The number is: %lf";


_asm {
    lea eax, input1
    push eax
    call printf_s
    add esp, 4

    lea eax, input_format
    push eax
    lea eax, afloat
    push eax
    call scanf_s
    add esp, 8

    sub esp, 8
    fstp [esp]

    lea eax, output
    push eax
    call printf
    add esp, 12

}
return 0;
}

结果:

您是否使用调试器查看寄存器/内存

fstp[esp]
非常可疑,因为此时ST0应该是空的。scanf返回一个整数,调用约定要求x87堆栈在调用/返回时为空,FP返回值除外

我忘记了当x87堆栈为空时进行FST时会发生什么。如果你得到零,这就可以解释了,因为这就是你要传递给printf的内容


添加esp,8
/
子esp,8
是完全冗余的。那样做没有意义。你可以把它拿出来。(或者对其进行注释,但将其保留在那里,以提醒您已通过重用堆栈上的arg空间进行了优化,而不是将其弹出并推送新内容。)


由于
scanf
在您传递的地址写入
double
,您可以通过让它在堆栈底部附近写入来避免复制它,然后将ESP调整到它的正下方。按下一个格式字符串,就可以调用printf了,
double
已经作为第二个参数出现在堆栈上

sub   esp, 8       ; reserve 8 bytes for storing a `double` on the stack
push  esp          ; push a pointer to the bottom of that 16B we just reserved
push  OFFSET input_format    ; (only works if it's in static storage, but it's a string constant so you should have done that instead of initializing a non-const array with a literal inside `main`.)
call  scanf        ; scanf("%lf", ESP_before_we_pushed_args)
add   esp, 8
; TODO: check return value and handle error

; esp now points at the double stored by scanf
push  OFFSET output_format
call  printf
add   esp, 12     ; "pop" the args: format string and the double we made space for before the scanf call.
如果您使用的调用约定/ABI要求您使用ESP 16B对齐进行函数调用,那么您不能将其缩短这么多:您需要一个
lea eax、[ESP+4]
/
push eax
或其他替代
push ESP
的东西,因为
double
不能正好位于scanf的第二个参数之上,但如果两个调用都对齐了堆栈16B,则它也可以是printf的第二个参数。因此,让scanf将
双精度
存储在更高的地址,并
添加esp,12
以访问它


IDK如果MSVC风格的内联asm首先保证任何类型的堆栈对齐。内联asm在某些方面似乎比在asm中编写整个函数更复杂。

您是否使用调试器查看寄存器/内存

fstp[esp]
非常可疑,因为此时ST0应该是空的。scanf返回一个整数,调用约定要求x87堆栈在调用/返回时为空,FP返回值除外

我忘记了当x87堆栈为空时进行FST时会发生什么。如果你得到零,这就可以解释了,因为这就是你要传递给printf的内容


添加esp,8
/
子esp,8
是完全冗余的。那样做没有意义。你可以把它拿出来。(或者对其进行注释,但将其保留在那里,以提醒您已通过重用堆栈上的arg空间进行了优化,而不是将其弹出并推送新内容。)


由于
scanf
在您传递的地址写入
double
,您可以通过让它在堆栈底部附近写入来避免复制它,然后将ESP调整到它的正下方。按下一个格式字符串,就可以调用printf了,
double
已经作为第二个参数出现在堆栈上

sub   esp, 8       ; reserve 8 bytes for storing a `double` on the stack
push  esp          ; push a pointer to the bottom of that 16B we just reserved
push  OFFSET input_format    ; (only works if it's in static storage, but it's a string constant so you should have done that instead of initializing a non-const array with a literal inside `main`.)
call  scanf        ; scanf("%lf", ESP_before_we_pushed_args)
add   esp, 8
; TODO: check return value and handle error

; esp now points at the double stored by scanf
push  OFFSET output_format
call  printf
add   esp, 12     ; "pop" the args: format string and the double we made space for before the scanf call.
如果您使用的调用约定/ABI要求您使用ESP 16B对齐进行函数调用,那么您不能将其缩短这么多:您需要一个
lea eax、[ESP+4]
/
push eax
或其他替代
push ESP
的东西,因为
double
不能正好位于scanf的第二个参数之上,但如果两个调用都对齐了堆栈16B,则它也可以是printf的第二个参数。因此,让scanf将
双精度
存储在更高的地址,并
添加esp,12
以访问它


IDK如果MSVC风格的内联asm首先保证任何类型的堆栈对齐。内联asm在某些方面似乎比在asm中编写整个函数更复杂。

您试图打印错误的值。事实上,代码应该只是导致无意义的内容被打印到终端上。您很幸运看到
0.0
。让我们具体看一下检索浮点值的代码部分,这是对
scanf\u s
的调用:

leaeax,输入\格式
推送eax
lea eax,漂浮
推送eax
打电话给scanf_s
添加esp,8
副esp,8
fstp[esp]
首先,我看不出在堆栈指针(
esp
)中添加8,然后立即从堆栈指针中减去8有什么逻辑。背对背地执行这两个操作只是相互抵消。因此,可以删除这两条说明

其次,将参数按错误的顺序推送到堆栈上。cdecl调用约定(CRT函数使用,包括
printf_s
scanf_s
)按从右到左的相反顺序传递参数。因此,要调用
scanf_s
,首先要推送输入应该存储到的浮点值的地址,然后推送格式控制字符串缓冲区的地址。您的代码是错误的,因为它将参数从左向右推。使用
printf\u s
,您会很幸运,因为您只传递了一个参数,但因为您将两个参数传递给
scanf\u s
,所以会发生不好的事情

第三个问题是,您似乎假设
scanf_s
直接返回输出

如果它返回了,并且您请求了一个浮点值,那么
cdecl
调用约定会让它在
FP(0)
中的浮点堆栈顶部返回该值,这样您就可以正确地弹出该值和