c++ - 从动态库 : Debug vs Release 加载 Fortran 函数

标签 c++ visual-studio dll fortran intel-fortran

我写了一些代码来加载一个用 Fortran 编译的动态库。 Fortran 库中导出的函数包括导出的 setter 和 getter。我正在尝试使用 Windows API 加载这些 setter 和 getter。虽然这适用于我在调试中构建的代码。它不适用于我的内置版本代码。在发行版中,当我尝试将 1.0f 传递给 set() 时,当我进入Fortran 代码。

编辑:我忘记提及的另一个观察结果。如果我只加载 setValue() 函数。我的问题完全消失了。只有当我从库中加载其他函数时,我才会开始遇到我所看到的问题。

编译器

  • 英特尔 Fortran 2017 更新 5
  • Visual Studio 2017 v15.5.2

调试

我已经确定,当我的 C++ 代码在发行版中编译时,我加载的 set() 函数会将 0.0f 传递给 fortran 函数。这是通过加载 fortran 库的调试版本并通过 Visual Studio 的调试器运行它来发现的。对我的代码的调试构建执行相同的操作会产生传递给 Fortran 函数的正确值。

我尝试了以下方法来弄清楚发生了什么:

  • 尝试在我的加载程序的调试和发布版本中加载已编译 Fortran 的调试和发布二进制文件。仅适用于我的加载程序调试版本。
  • 重建 Fortran 代码以验证编译器标志,例如用于调试的多线程调试 DLL 和用于发布的多线程 DLL。
  • 对 fortran 二进制文件进行转储以验证函数地址​​是否已正确加载;他们是。

FORTRAN

    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);

我很迷茫。对这里可能发生的事情有什么想法或建议吗?

完整的可编译示例

以下是指向我遇到的问题的完整可编译示例的链接。在有更多时间花在它身上之后。看来我的问题源于我尝试使用上述代码制作包装器。

fortran_value.dll

fortran_value_test.exe

最佳答案

阅读我的问题的回复后,我花了更多时间调试 Fortran 代码并进行了更多研究。正如在对我的问题的答复中所讨论的,调用约定不匹配。通过在我的 Fortran 代码中使用 bind(c),我的问题得到了解决。

Since Fortran 2003 (ISO/IEC 1539-1:2004(E)) there is a standardized way to generate procedure and derived-type declarations and global variables which are interoperable with C (ISO/IEC 9899:1999). The bind(C) attribute has been added to inform the compiler that a symbol shall be interoperable with C; also, some constraints are added. Note, however, that not all C features have a Fortran equivalent or vice versa. For instance, neither C’s unsigned integers nor C’s functions with variable number of arguments have an equivalent in 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

关于c++ - 从动态库 : Debug vs Release 加载 Fortran 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47927471/

相关文章:

c# - 使用 C# 程序启动 Dll

c++ - OpenSSL加密/解密

c++ - 以不同方式打印整数指针元素时的不同结果

c++ - 为什么 STL 中的 priority_queue 不遵循严格的弱排序?

visual-studio - 缺少Visual Studio 2017安装项目

asp.net-mvc - Visual Studio 提示使用 Razor 语法 1.0 安装 ASP.NET 网页

c++ - Linderdaum 引擎中奇怪的多个类名

c# - 在 C# (WPF) 中显示 mysql 的整个表

c# - 从Rust向C#DLL发送数据时发生STATUS_HEAP_CORRUPTION错误

c - 应用程序可执行文件和 3d 方库之间的嗅探函数调用