C++调用Fortran编写的DLL时对可变数组的应对方法
由于C++程序本身在语言的通用性上有着巨大的优势,常常会用来进行底层或框架的编程,而Fortran由于其强大的矩阵计算功能,程序员或者科研工作者常常拿来进行算法上的编写,这中间就产生了他们之间参数传递的问题。本文就个人经验对C++调用Fortran编写的动态链接库中遇到可变数组时如何处理进行总结,以期更好的掌握混编的强大功能。
1. C++调用Fortran时的规则
C++在调用Fortran的DLL库时,一般可以采用显示链接,对调用约定进行设定,如果调用约定没有事先说清,会产生参数传递不对的情况。Fortran默认的调用约定是_stdcall方式,而C++默认的调用约定是_cdecl方式,所以这两者要选择一个进行调整,统一到一种约定上来。这里我们选择调整C++来进行调整,主要是因为C++语言更加自由,可选择性高。
显式调用的步骤分为以下几步:
- 加载dll
#include<window.h>
HMODULE h=LoadLibrary(L"xxx.dll");
- 获取函数地址
typedef void(*FUNC)(double* x, int* y, double z[200], double* A)
- 利用函数指针调用函数
FUNC func=(FUNC)GetProcAddress(h,"func");
- 释放dll
FreeLibrary(h);
上面是显式动态链接库加载的一般方式,但是正如开头讲的,由于Fortran和C++默认调用约定不同,这里要进行设置,在第2步时,需如下写
typedef void(_stdcall* FUNC)(double* x, int* y, double z[200], double* A);
可以看到本行增加了对调用约定的设置。
本处的具体知识可以参考黄强老师的视频教程
C++动态链接库视频教程(Windows动态链接库)
2. 参数传递的要求
C++在调用Fortran的动态链接库时,默认的方式是地址传递,所以上面的第2步进行函数地址传递时,采用的均是指针变量形式,包括z[200]
实际上也是传递的数组地址。
对于可变数组,C++一般是需要进行new操作,及以下操作:
int Num_A = y;
double* A = new double[Num_A];
这样就可以建立一个动态的数组A,数组大小可以通过Num_A来进行设定。那么在Fortran中,如何进行设定呢?
subroutine FUNC(x , y , z , A)
implicit none
!DEC$ ATTRIBUTES DLLEXPORT :: FUNC
real(8), intent(in) :: x
integer(4),intent(in) :: y
real(8), intent(out) :: z(200)
real(8) :: A(y)
...
end subroutine FUNC
可以看到A(y)
对可变的数组A进行了定义,这样就可以和C++中的可变数组进行同步。