Я пытался отладить этот код, который вызывает подпрограмму 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 Binding. Это обеспечивает способ взаимодействия Fortran и C (и C ++ через ‘extern «C»‘), который является частью стандарта языка Fortran и поэтому независим от компилятора и платформы. Такие заявления, как «Фортран передает по ссылке» и что компиляторы Фортрана добавляют подчеркивания (сделанные на веб-странице, связанной в другом ответе), больше не нужны. Программист может указать соглашения о вызовах, совместимые с C, и точные имена. Это если вам разрешено изменять код Фортрана. Или вы можете написать подпрограмму склейки в Фортране между подпрограммой C / C ++ и оригинальной подпрограммой Фортрана. В Stackoverflow есть много предыдущих вопросов / ответов о привязке ISO C. Есть примеры в руководстве Gfortran.
void (*fex)(int, double, double[], double[])
не совпадает
void FEX (int &NEQ, double &T, double Y[], double YDOT[])
Вы объявили аргумент 3 из DLSODE
быть 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.
Это касается сообщений об ошибках, которые вы опубликовали, и всех ошибок, которые я видел.
Также, этот кажется хорошим справочным материалом для того, что вы пытаетесь сделать.