gpt4 book ai didi

c++ - 从 Fortran 调用特定的 C++ DLL

转载 作者:行者123 更新时间:2023-12-02 10:26:28 32 4
gpt4 key购买 nike

我收到了一个用 C++ 制作的 DLL,我正在构建一个 Fortran 程序来调用 C++ DLL。
我的编译器 (gfortran) 没有显示任何警告,但它在运行时崩溃,描述如下:

    forrtl: severe (157): Program Exception - access violation
Image PC Routine Line Source
MainDLL_v10.dll 0B7A6B01 Unknown Unknown Unknown
MainDLL_v10.dll 0B7A1BEF Unknown Unknown Unknown
...
我想我的调用参数有问题。
C++ DLL 包括以下内容:
    #include <DllClasses.h>
...
extern "C"
{
...
__declspec(dllexport) RESULT __cdecl Initialize(char *DllNames[], int NumberOfDlls, char *InputFile, char *OutputFile, char *CtrlVersion, int InitState)
{
...
}
...
} // extern C
我的 Fortran 程序是这样写的。这是我包含之前的代码的一部分。
    ABSTRACT INTERFACE
SUBROUTINE Initialize(PDLLNames, NumberOfDLLs, PInputfile, Poutputfile, CtrlVersion, InitState) BIND(C)
USE, INTRINSIC :: ISO_C_Binding
IMPLICIT NONE
!DEC$ ATTRIBUTES C :: Initialize
CHARACTER(KIND=C_CHAR), INTENT(IN ), DIMENSION(9) :: PDLLNames
INTEGER(C_INT), INTENT(IN ) :: NumberOfDLLs
CHARACTER(KIND=C_CHAR), INTENT(IN ) :: PInputfile
CHARACTER(KIND=C_CHAR), INTENT(INOUT) :: Poutputfile
CHARACTER(KIND=C_CHAR), INTENT(IN ) :: CtrlVersion
INTEGER(C_INT), INTENT(IN ) :: InitState
END SUBROUTINE Initialize
SUBROUTINE MainDll(InputSignals, OutputSignals, PErrorMessage) BIND(C)
USE, INTRINSIC :: ISO_C_Binding
IMPLICIT NONE
!DEC$ ATTRIBUTES C :: MainDll
REAL(C_DOUBLE), INTENT(IN ) :: InputSignals (*)
REAL(C_DOUBLE), INTENT( OUT) :: OutputSignals (*)
CHARACTER(KIND=C_CHAR), INTENT( OUT) :: PErrorMessage (*)
END SUBROUTINE MainDll
END INTERFACE
这是我在程序中的一部分 Fortran 代码。
        ! Variables for dll interface
PROCEDURE(Initialize), BIND(C), POINTER :: Initialize_proc
INTEGER(C_INT) :: NumberOfDLLs=9, InitState
CHARACTER(KIND=C_CHAR, LEN=56), TARGET :: MainDll, DLLInputfile, DLLOutputfile, StateControllerName
CHARACTER(KIND=C_CHAR, LEN=56), TARGET, DIMENSION(9) :: DLLname
CHARACTER(KIND=C_CHAR, LEN=56), POINTER :: PoInputfile, PoOutputfile, PoStateControllerName
CHARACTER(KIND=C_CHAR, LEN=56), POINTER, DIMENSION(9) :: PoDLLname(:)
PoInputfile => DLLInputfile
PoOutputfile => DLLOutputfile
PoStateControllerName => StateControllerName
PoDLLname(1:) => DLLname(1:9)
...
! Load DLL
module_handle = LoadLibrary(MainDll // C_NULL_CHAR)
proc_address = GetProcAddress( module_handle, C_CHAR_'Initialize' // C_NULL_CHAR )
! Call Initialize function in DLL
CALL C_F_PROCPOINTER(proc_address, Initialize_proc)
CALL Initialize_proc(PoDLLname, NumberOfDLLs, PoInputfile, PoOutputfile, PoStateControllerName, InitState)

最佳答案

您的 C 函数的特征与相关 Fortran 接口(interface)主体所描述的特征不匹配。
在 Fortran 中调用可互操作过程(具有 BIND(C) 的过程)时,不带 VALUE 属性的标量参数通过引用传递给 C++ 函数。如果希望参数按值传递,则需要在 Fortran 端添加 VALUE 属性。
例如,在 C++ 片段中:

__declspec(dllexport) RESULT __cdecl Initialize(... int NumberOfDlls
NumberOfDlls 是按值传递的,但 Fortran 显示:
SUBROUTINE Initialize(... NumberOfDLLs, ...) BIND(C)
...
INTEGER(C_INT), INTENT(IN) :: NumberOfDLLs
无值属性 - Fortran 参数对应于 int *NumberOfDlls 的 C++ 参数.对于按值传递,请使用 Fortran 参数声明:
  INTEGER(C_INT), INTENT(IN), VALUE :: NumberOfDLLs   
您的 Fortran 接口(interface)还包括用于 gfortran 之外的一系列编译器(今天由 Intel Fortran 代表)的编译器指令 ( !DEC$ ATTRIBUTES...)。该指令将更改该系列编译器的 Fortran 端参数的行为,可能以与 C 函数匹配的方式。但 gfortran 不理解该指令 - 它认为它只是一个注释。
gfortran 有自己的等效指令,但使用类似的指令反射(reflect)了语言标准没有 C 互操作性支持的时代。
由于编译器开始支持 Fortran 2003,您最好使用标准语言功能来管理互操作性 - 将 VALUE 添加到需要它的参数(也包括 InitState),并删除指令。
您的问题中未显示有关 Windows API 的 LoadLibrary 和 GetProcAddress 的细节。我假设它们已针对所有可能使用的编译器进行了正确描述。
在 Fortran 中准备参数的方式有一个建议(使用了很多指针 - 为什么??)关于调用 C 代码的要求的其他误解。

关于c++ - 从 Fortran 调用特定的 C++ DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64281930/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com