C++ 从动态库加载Fortran函数:调试与发布
我编写了一些代码来加载用Fortran编译的动态库。Fortran库中导出的函数中有导出的setter和getter。我正在尝试使用Windows API加载这些setter和getter。而这适用于我的代码内置调试。它不适用于我的代码内置版本。在发行版中,当我尝试将C++ 从动态库加载Fortran函数:调试与发布,c++,visual-studio,dll,fortran,intel-fortran,C++,Visual Studio,Dll,Fortran,Intel Fortran,我编写了一些代码来加载用Fortran编译的动态库。Fortran库中导出的函数中有导出的setter和getter。我正在尝试使用Windows API加载这些setter和getter。而这适用于我的代码内置调试。它不适用于我的代码内置版本。在发行版中,当我尝试将1.0f传递到set()时,当我进入fortran代码时,我在调试器中看到0.0f 编辑:另一个我忘了提到的观察结果。如果我只加载setValue()函数。我的问题完全解决了。只有当我从库中加载其他函数时,我才开始出现我看到的问题
1.0f
传递到set()
时,当我进入fortran代码时,我在调试器中看到0.0f
编辑:另一个我忘了提到的观察结果。如果我只加载setValue()
函数。我的问题完全解决了。只有当我从库中加载其他函数时,我才开始出现我看到的问题
编译器
- 英特尔Fortran 2017更新5
- Visual Studio 2017 v15.5.2
我确定,当我的C++代码在版本中编译时,我的加载<代码> SET()//Cuff>函数将通过<代码> 0.0f 到FORTRAN函数。这是通过加载fortran库的调试版本并通过Visual Studio的调试器运行发现的。对我的代码的调试构建执行相同的操作会产生传递给fortran函数的正确值
为了弄清发生了什么,我尝试了以下方法:- 尝试在我的加载程序的调试版本和发布版本中加载已编译Fortran的调试和发布二进制文件。仅适用于我的加载程序调试版本
- 重新生成Fortran代码验证编译器标志,例如用于调试的多线程调试DLL和用于发布的多线程DLL
- 执行fortran二进制文件的dumpbin,以验证函数地址是否正确加载;是的
REAL FUNCTION getValue()
!DEC$ ATTRIBUTES DLLEXPORT, c:: getValue
IMPLICIT NONE
INCLUDE 'VALUE.CMN'
getValue = VAL
RETURN
END FUNCTION getValue
SUBROUTINE setValue(x)
!DEC$ ATTRIBUTES DLLEXPORT, c:: setValue
IMPLICIT NONE
INCLUDE 'VALUE.CMN'
REAL, INTENT(IN) :: x
VAL = x
END SUBROUTINE setValue
C++
const auto handle = reinterpret_cast<HMODULE>(LoadLibrary("fortran_value.dll"));
typedef void(*Set)(float&);
typedef float(*Get)(void);
const auto set = reinterpret_cast<Set>(GetProcAddress(handle, "setvalue"));
const auto get = reinterpret_cast<Get>(GetProcAddress(handle, "getvalue"));
auto value = 1.0f;
// 0.0f gets set to the internal fotran variable when this code is compile in release.
set(value);
// Only succeeds when this code is compiled in Debug.
// get() returns 0.0f when this code is compiled in Release.
if(value == get())
{
std::cout << "Success!\n";
}
else
{
std::cout << "Fail!\n";
}
FreeLibrary(handle);
const auto handle=reinterpret_cast(加载库(“fortran_value.dll”);
类型定义无效(*套)(浮动和);
类型定义浮动(*Get)(无效);
const auto set=reinterpret_cast(GetProcAddress(句柄,“setvalue”);
const auto get=reinterpret_cast(GetProcAddress(句柄,“getvalue”);
自动值=1.0f;
//在版本中编译此代码时,将0.0f设置为内部fotran变量。
设置(值);
//仅在调试中编译此代码时成功。
//在版本中编译此代码时,get()返回0.0f。
if(value==get())
{
std::cout在阅读了对我的问题的回答之后,我花了更多的时间调试fortran代码并做了更多的研究。正如在对我的问题的回答中所讨论的,调用约定不匹配。通过在我的fortran代码中使用bind(c),我的问题得到了解决
自Fortran 2003(ISO/IEC 1539-1:2004(E))以来,有一种标准化的方法来生成过程和派生类型声明以及与C(ISO/IEC 9899:1999)互操作的全局变量属性已添加,以通知编译器符号应可与C互操作;此外,还添加了一些约束。但是,请注意,并非所有C功能都具有Fortran等效项,反之亦然。例如,C的无符号整数或具有可变参数数的C函数在Fortran中都没有等效项>
什么是“不工作”?到底发生了什么?有什么错误消息吗?我更新了我的C++代码,有一些注释解释了我在调试器中看到的值。在发行版中,我通过1.0f通过代码> SET()。
但是当我单步执行fortran代码时,我看到的是0.0f。在调试中,它按预期工作,我传入1.0f,在调试器中看到的是1.0f。请非常非常怀疑在调试器中检查变量时看到的内容。我强烈建议单步执行汇编程序指令,并查看它正在执行的操作。这是吗是32位还是64位?我想您的调用约定不匹配,或者您对调试器显示的内容感到困惑。这只是64位。我的计算机上只安装了64位fortran编译器。
REAL FUNCTION getValue() bind(c)
!DEC$ ATTRIBUTES DLLEXPORT :: getValue
IMPLICIT NONE
INCLUDE 'VALUE.CMN'
getValue = VAL
RETURN
END FUNCTION getValue
SUBROUTINE setValue(x) bind(c)
!DEC$ ATTRIBUTES DLLEXPORT :: setValue
IMPLICIT NONE
INCLUDE 'VALUE.CMN'
REAL, INTENT(IN) :: x
VAL = x
END SUBROUTINE setValue