【问题标题】:Passing C++ function pointers to Fortran subroutine将 C++ 函数指针传递给 Fortran 子例程
【发布时间】:2012-09-12 15:40:59
【问题描述】:

我一直在尝试调试这个调用 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’

谢谢,

【问题讨论】:

  • 如果您在错误消息中添加带有行号的 cmets 将非常有帮助,否则我们必须自己弄清楚它们,这很痛苦。

标签: c++ arrays pointers parameters fortran


【解决方案1】:

将 C 或 C++ 与 Fortran 接口的现代方法是使用 Fortran ISO C 绑定。这提供了连接 Fortran 和 C(以及通过'extern "C"' 的 C++)的方法,它是 Fortran 语言标准的一部分,因此与编译器和平台无关。不再需要诸如“Fortran 通过引用传递”之类的声明以及 Fortran 编译器附加下划线(在另一个答案中链接的网页中制作)。程序员可以指定与 C 兼容的调用约定和准确的名称。这是如果您被允许修改 Fortran 代码。或者,您可以在 C/C++ 例程和原始 Fortran 例程之间用 Fortran 编写粘合例程。 Stackoverflow 上有很多关于 ISO C 绑定的问题/答案。 gfortran 手册中有示例。

【讨论】:

    【解决方案2】:
    void (*fex)(int, double, double[], double[])
    

    不匹配

    void FEX (int &NEQ, double &T, double Y[], double YDOT[])
    

    您已将 DLSODE 的参数 3 声明为 double *Y[],这是一个指向 double 的指针数组,但这应该只是 double Y[]。你传入&amp;YY 被声明为double Y[3],但你应该传入Y

    在你的JEX 声明中,你有double &amp;PD[3][3],但你只需要double PD[3][3]

    您应该将3*pow(10,7) 之类的计算表示为300000003E7,它们是编译时常量。

    还要记住,C 和 C++ 对二维数组使用行优先顺序,但 FORTRAN 使用列优先顺序。当您通过 C/FORTRAN 边界传递数组时,这将产生转置数组的效果。

    这涵盖了您发布的错误消息以及我看到的所有错误。

    另外,this 似乎是您尝试做的一个很好的参考。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-06
      • 1970-01-01
      • 1970-01-01
      • 2012-02-22
      • 1970-01-01
      • 1970-01-01
      • 2011-04-17
      • 1970-01-01
      相关资源
      最近更新 更多