c++ - MATLAB 因 calllib(C++ .h 文件和 FORTRAN .dll)而崩溃

标签 c++ matlab dll fortran

我正在尝试在 MATLAB 中包含一个基于 FORTRAN 的外部(使用英特尔 Fortran 编译器编译)DLL。由于它是外部的,我无法对 DLL 的运行时库进行任何调整。目前,我用 C++ 编写了一个附带的头文件,以便能够调用 DLL。使用 loadlibrary 将库加载到 MATLAB 中(没有错误 - 一个警告),但是,当使用 calllib 时,MATLAB 崩溃并且不提供错误。

我认为以下原因之一可能是造成这种情况的原因,但由于我对使用 DLL(尤其是使用 C++ 进行编码)没有经验,所以我自己还没有发现错误。

  • 还有一个我从供应商那里得到的 .lib 文件,但我还没有将它合并到 MATLAB 文件或 C++ 头文件中。
  • FILEAFILEB 变量是输入到 DLL 的两个文本文件的路径,我想我可能没有正确地将它们合并到 C++ 中。
  • mHeader文件(MATLAB头文件)中,stdcall只在注释部分提到,在编码部分没有提到。

C++头文件代码和我的MATLAB脚本如下所示:

#ifndef _MYMODEL
#define _MYMODEL
#ifdef __cplusplus
extern "C" {
#endif // _cplusplus
    // Functions and data types defined
     void __stdcall MYFUN(char FILEA[], char FILEB[], int *IDTask, int 
    *nErrorCode, int *ErrorCode, double *Props, double *Out1, double *Out2, 
    double *Out3, double *Out4, double *Out5);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // !_MYMODEL      

MATLAB(r2018b):

%% Input to model
FILEA       = 'PATH\FILEA.txt';
FILEB       = 'PATH\FILEB.txt';
IDTask      = 1; %Multiple tasks possible in the .dll
%% Determine pointers
lpFILEA         = libpointer('cstring', FILEA);
lpFILEB         = libpointer('cstring', FILEB);
lpIDTask        = libpointer('int32Ptr', IDTask);
lpnErrorCode    = libpointer('int32Ptr');
lpErrorCode     = libpointer('int32Ptr');
lpProps         = libpointer('doublePtr');
lpOut1          = libpointer('doublePtr');
lpOut2          = libpointer('doublePtr');
lpOut3          = libpointer('doublePtr');     
lpOut4          = libpointer('doublePtr');
lpOut5          = libpointer('doublePtr');      

%% LoadLibrary
    [notfound, warnings] = loadlibrary('MYMODEL.dll','MYMODEL.h' ,'mfilename', 'mHeader');
%% Call .dll
[~,~, ~, nErrorOut, ErrorCodeOut, PropsOut, Out1_, ~, ~, Out4_, Out5_] ...
    = calllib('MYMODEL', 'MYFUN', lpFILEA, ...
    lpFILEB, lpIDTask, lpnErrorCode, lpErrorCode, lpProps, lpOut1, ...
    lpOut2, lpOut3, lpOut4, lpOut5);

预先感谢您的帮助!

最佳答案

我认为您的问题是您将 NULL 指针传递给 FORTRAN 函数,然后该函数将尝试写入非法地址。您需要先为输出分配内存,然后将指向该内存的指针传递给您的函数。像这样:

% Input to model
FILEA       = 'PATH\FILEA.txt';
FILEB       = 'PATH\FILEB.txt';
IDTask      = 1;
% Determine pointers
lpnErrorCode    = libpointer('int32Ptr',0); % !!! You need to know the size of these outputs!
lpErrorCode     = libpointer('int32Ptr',0);
lpProps         = libpointer('doublePtr',zeros(10,1)); 
lpOut1          = libpointer('doublePtr',zeros(4,1));
lpOut2          = libpointer('doublePtr',zeros(8,1));
lpOut3          = libpointer('doublePtr',zeros(2,1));     
lpOut4          = libpointer('doublePtr',zeros(5,1));
lpOut5          = libpointer('doublePtr',zeros(7,1));      

% LoadLibrary
[notfound, warnings] = loadlibrary('MYMODEL.dll','MYMODEL.h' ,'mfilename', 'mHeader');
% Call DLL
calllib('MYMODEL', 'MYFUN', [uint8(FILEA),0], [uint8(FILEB),0], ...
        IDTask, lpnErrorCode, lpErrorCode, lpProps, lpOut1, ...
        lpOut2, lpOut3, lpOut4, lpOut5);
% Get output values
nErrorCode = lpnErrorCode.Value;
clear lpnErrorCode
ErrorCode = lpErrorCode.Value;
clear lpErrorCode
% ... etc.

对于这些输出中的每一个,我都使用 zeros 函数创建了数据。前两个是标量值(一个数据元素),其他是各种大小的数组。我不知道你的 FORTRAN 函数在那里期望什么,所以我只是做了一些大小。请检查您的函数以查看每个指针应指向的内存大小。

请注意,我还更改了将输入数据传递给函数的方式。 MATLAB 应自动将数据转换为正确的类型。 [uint8(FILEA),0] 从 MATLAB 字符数组 FILEA 创建一个以零结尾的 c 风格字符串。在 C 中,字符串必须以零结尾。我不知道 FORTRAN 如何确定字符串的长度,我认为它是相同的,因为该函数使用“C”接口(interface)。

关于c++ - MATLAB 因 calllib(C++ .h 文件和 FORTRAN .dll)而崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54304095/

相关文章:

c++ - Ubuntu 18+ 上缺少 Asan 动态运行时

matlab - 使 Matlab 函数在任何目录下都可用。

python - NumPy中MATLAB的repmat相当于什么

dll - PKCS11 Windows 无效引擎 YubiHSM2

c# - 从 C# 调用非托管 (C++) 函数时出现 PInvoke 错误

java - winio64.dll 中有哪些方法以及如何使用它们

c++ - 分配 io_service 工作 - boost::asio

c++ - 从类返回只读二维数组

android - 我可以在 Android 设备上运行 Simulink 吗?

c++ - 如果语句在我的代码中不起作用