2012-09-12 67 views
1

我一直在試圖調試這個調用Fortran子程序DLSODE的代碼。這個子程序的兩個參數是函數FEX和JEX,我將它們作爲函數指針傳遞。據我所知,Fortran子程序使用的任何函數都必須具有引用參數調用,因爲fortran不接受按值調用。將C++函數指針傳遞給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’ 

謝謝

+0

如果您在錯誤信息中添加了行號的註釋,這將非常有幫助,否則我們必須自己弄清楚它們,這是一個痛苦。 – Wug

回答

3
void (*fex)(int, double, double[], double[]) 

沒有的DLSODE 3匹配

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

你宣佈一個參數是double *Y[] ,一組po inters到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-d數組的行優先順序,但FORTRAN使用列優先順序。這會在您將數組傳遞給C/FORTRAN邊界時產生轉置數組的效果。

這涵蓋了您發佈的錯誤消息和我見過的所有錯誤。

此外,this似乎是你想要做的很好的參考。

4

將C或C++接口到Fortran的現代方式是使用Fortran ISO C綁定。這提供了通過Fortran語言標準的一部分接口Fortran和C(以及通過'extern「C'')進行接口的方式,因此是獨立於編譯器和平臺的。諸如「Fortran傳遞參考」之類的語句以及Fortran編譯器追加下劃線(在另一個答案中鏈接的網頁中進行)不再需要。程序員可以指定與C兼容的調用約定和精確的名稱。這是如果您允許修改Fortran代碼。或者,您可以在C/C++例程和原始Fortran例程之間的Fortran中編寫膠水例程。關於ISO C綁定的Stackoverflow有很多以前的問題/答案。 gfortran手冊中有例子。

+2

+1舊的方法應儘快忘記。 –