从动态库加载 Fortran 函数:调试与发布

Loading Fortran function from dynamic library: Debug vs Release

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

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

编译器

正在调试

我确定当我的 C++ 代码在发行版中编译时,我加载的 set() 函数会将 0.0f 传递给 fortran 函数。这是通过加载 fortran 库的调试版本并通过 Visual Studio 的调试器 运行 发现的。对我的代码的调试版本执行相同的操作会产生传递给 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