将C++函数指针传递到Fortran子例程
Passing C++ function pointers to Fortran subroutine
我一直在尝试调试这段代码,它调用Fortran子程序DLSODE。这个子程序的两个参数是函数,FEX和JEX,我将它们作为函数指针传递。据我所知,fortran子例程使用的任何函数都必须具有按引用调用参数,因为fortran不接受按值调用。
我的问题是,我得到的错误似乎表明我在指针的函数声明中声明的数据类型与下面的函数定义之间存在差异,并且我没有成功调试它。
#include <iostream>
#include <cmath>
using namespace std;
extern"C" {void DLSODE_(void (*fex)(int, double, double[], double[]), int *NEQ,
double *Y[], double *T, double *TOUT, int *ITOL,
double *RTOL, double *ATOL[], int *ITASK, int *ISTATE,
int *IOPT, double *RWORK[], int *LRW, int *IWORK[],
int *LIW, void (*jex)(int, double, double[], int,
int, double [3][3], int),
int *MF);
}
void FEX (int &NEQ, double &T, double Y[], int YDOT[]);
void JEX (int &NEQ, double &T, double Y[], int &ML, int &MU, double PD[3][3],
int &NRPD);
int main(){
int IOPT, IOUT, ISTATE, ITASK, ITOL, IWORK[23], LIW, LRW, MF, NEQ, ICOUNT=1;
double ATOL[3], RTOL, RWORK[58], T, TOUT, Y[3];
NEQ = 3;
Y[0] = 1;
Y[1] = 0;
Y[2] = 0;
T = 0;
TOUT = 0.4;
ITOL = 2;
RTOL = pow(10,-4);
ATOL[0] = pow(10,-6);
ATOL[1] = pow(10,-10);
ATOL[2] = pow(10,-6);
ITASK = 1;
ISTATE = 1;
IOPT = 0;
LRW = 58;
LIW = 23;
MF = 21;
for (ICOUNT; ICOUNT <13; ICOUNT++)
{
DLSODE_(&FEX, &NEQ, &Y, &T, &TOUT, &ITOL, &RTOL, &ATOL, &ITASK, &ISTATE,
&IOPT, &RWORK, &LRW, &IWORK, &LIW, &JEX, &MF);
cout<<"At t= "<<T<<" y= "<<Y[1]<<" "<<Y[2]<<" "<<Y[3]<<"n";
}
}
void FEX (int &NEQ, double &T, double Y[], double YDOT[]){
YDOT[0] = -.04*Y[0] + pow(10,4)*Y[1]*Y[2];
YDOT[2] = 3*pow(10,7)*Y[1]*Y[1];
YDOT[1] = -YDOT[0] - YDOT[2];
}
void JEX (int &NEQ, double &T, double Y[], int &ML, int &MU, double &PD[3][3],
int &NRPD){
PD[0][0] = -.04;
PD[0][1] = 1*pow(10,4)*Y[2];
PD[0][2] = 1*pow(10,4)*Y[1];
PD[1][0] = .04;
PD[1][2] = -PD[0][2];
PD[2][1] = 6*pow(10,7)*Y[1];
PD[1][1] = -PD[0][1] - PD[2][1];
}
错误消息是
cversion1.cpp: In function ‘int main()’:
cversion1.cpp:44:52: error: invalid conversion from ‘void (*)(int&, double&, double*, int*)’ to ‘void (*)(int, double, double*, double*)’
cversion1.cpp:44:52: error: cannot convert ‘double (*)[3]’ to ‘double**’ for argument ‘3’ to ‘void DLSODE_(void (*)(int, double, double*, double*), int*, double**, double*, double*, int*, double*, double**, int*, int*, int*, double**, int*, int**, int*, void (*)(int, double, double*, int, int, double (*)[3], int), int*)’
cversion1.cpp: At global scope:
cversion1.cpp:55:77: error: declaration of ‘PD’ as array of references
cversion1.cpp:55:78: error: expected ‘)’ before ‘,’ token
cversion1.cpp:56:4: error: expected unqualified-id before ‘int’
谢谢你,
将C或C++与Fortran接口的现代方法是使用Fortran ISO C绑定。这提供了一种接口Fortran和C(以及通过"extern"C"连接C++)的方法,后者是Fortran语言标准的一部分,因此与编译器和平台无关。不再需要诸如"Fortran通过引用传递"和Fortran编译器附加下划线(在另一个答案中链接的网页中生成)之类的语句。程序员可以指定与C兼容的调用约定和精确的名称。这是允许您修改Fortran代码的情况。或者,您可以在C/C++例程和原始Fortran例程之间用Fortran编写一个粘合例程。关于ISO C绑定的Stackoverflow,以前有很多问题/答案。gfortran手册中有一些例子。
void (*fex)(int, double, double[], double[])
与不匹配
void FEX (int &NEQ, double &T, double Y[], double YDOT[])
您已经将DLSODE
的参数3声明为double *Y[]
,一个指向double
的指针数组,但它应该只是double Y[]
。您正在传递&Y
,并且Y
被声明为double Y[3]
,但您应该只传递Y
。
在您的JEX
声明中,您有double &PD[3][3]
,但这里只需要double PD[3][3]
。
应该将类似3*pow(10,7)
的计算表示为30000000
或3E7
,它们是编译时间常数。
还要记住,C和C++对二维数组使用行主序,但FORTRAN使用列主序。当您通过C/FORTRAN边界时,这将具有转置数组的效果。
这涵盖了你发布的错误消息和我看到的所有错误。
此外,这似乎是你尝试做什么的一个很好的参考。
- 子例程,不使用 pow,并带有参数和返回
- 如何将C++子例程链接到 x86 程序集程序?
- 调用子例程时类型不匹配
- 将分配给C++数组传递给 Fortran 子例程
- Android Studio 3.1.2 - 无法运行C++子例程"No implementation found for Java.lang.String..."
- 试图在C 中调用Fortran子例程
- Visual MSVC C 调用GFORTRAN子例程
- 从C 调用Fortran子例程会产生非法参数值
- 将类对象指针传递给默认构造函数(C 子例程)
- 如何从子例程函数获取到 main 函数的返回值
- 确定未在 Fortran 子例程顶部声明的变量类型
- 子例程在 MIPS 上调用了两次
- 从 C++ 调用 Fortran 子例程
- 将C++函数指针传递到Fortran子例程
- 如何使用传递到当前子例程中的参数调用不同的子例程(用于递归)
- 在主程序或函数子例程中使用数组的差异
- 如何将 fortran 子例程链接到 cpp 主程序
- 将C++数组传递给Fortran子例程会导致nan值出现在结果中
- 单元测试不会失败,但挂在子例程调用上
- 奇怪的bug-子例程只运行一个cout