1

Fortran サブルーチン DLSODE を呼び出すこのコードをデバッグしようとしています。このサブルーチンの 2 つのパラメーターは関数 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’

ありがとうございました、

4

2 に答える 2

4

C または C++ を Fortran に接続する最新の方法は、Fortran ISO C バインディングを使用することです。これにより、Fortran 言語標準の一部である Fortran と C (および「extern "C"」を介した C++) とのインターフェイスが提供されるため、コンパイラとプラットフォームに依存しません。「Fortranは参照渡し」などのステートメントや、Fortranコンパイラがアンダースコアを追加する(他の回答にリンクされているWebページで作成された)などのステートメントは不要になりました。プログラマーは、C と互換性のある呼び出し規約と正確な名前を指定できます。これは、Fortran コードの変更が許可されている場合です。または、C/C++ ルーチンと元の Fortran ルーチンの間に Fortran でグルー ルーチンを記述できます。ISO C バインディングに関する Stackoverflow に関する以前の質問/回答が多数あります。gfortran マニュアルに例があります。

于 2012-09-13T03:43:34.530 に答える
3
void (*fex)(int, double, double[], double[])

一致していません

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

の引数 3 をDLSODEdouble *Y[]のポインタの配列であると宣言しましdoubleたが、これは である必要がありますdouble Y[]。を渡していますが&YYとして宣言されてdouble Y[3]いますが、そのまま渡す必要がありますY

あなたのJEX宣言には がありますがdouble &PD[3][3]、ここに欲しいだけですdouble PD[3][3]

コンパイル時の定数であるやのよう3*pow(10,7)に計算を表現する必要があります。300000003E7

また、C と C++ は 2 次元配列に行優先順序を使用しますが、FORTRAN は列優先順序を使用することに注意してください。これにより、C/FORTRAN 境界を越えて配列を渡すときに、配列を転置する効果が得られます。

それはあなたが投稿したエラーメッセージと私が見たすべてのエラーをカバーしています.

また、これはあなたがやろうとしていることの良い参考資料のようです。

于 2012-09-12T16:19:06.343 に答える