(1) Fortran 環境を初期化するために、 hf_fint((char *)NULL); を呼ぶ。 (2) common 変数の参照 hbook 等で common 領域を確保する必要があるときは、fortran プログラムを 用意して、その中で common 領域を確保することが必要である。また、common 中の変数を参照するには、fortran プログラムで変数を引数として返すプログラムを 用意することが必要である。 そのような、C++ から呼べるようなfortran プログラムをコンパイルするには、 fortran コンパイラーのオプションは F77FLAGS = -i,E,U,P,PL,LT,L,EU,CL,CU,BL -W0,"LANGLVL(CONTI199,DARG(L),H8000)" である。 Fortran のI/O で作成されたバイナリーファイルにアクセスするにも、 Fortran でのインターフェースプログラムを作成することが必要である。 (3) C++ ソースコードの書き方の例。 Fortran プログラム、subfort、をC++ から呼び出す例を示す。 c ************************************************ c *** example of fortran subroutine c subroutine subfort(i, x, str1, array, str2) integer*4 i real*4 x, array(20) character*(*) str1, str2 c ....... return end // *********************************************** extern "C" { extern void subfort_(int *i, float *x, char *str1, float array[], char *str2, int len1, int len2); }; .... int i; float x; float array[]; char *str1="Character example" ; char str2[30]; int len1=strlen(str1) ; int len2=strlen(str2); subfort_(&i, &x, str1, array, str2, len1, len2); // Fortran program の呼び出し 上の例にあるように、C++ で関数プロトタイプの宣言は extern "C" を使って行う、 Fortran プログラムへ引数を渡す方法は、アドレス渡しである、文字変数の長さは 引数の最後に値渡しの引数を付けて行う、の3点に注意すればよい。 (4) Fortran library Fortran ライブラリーの指定は、コンパイラーがf77 かf90 かに応じて、 -lf77 -lhfmath f77 の時 -lf90 -lhf90math f90の時 を指定する。 (注:ccjlcでのfortran コンパイラーのデフォルトはf77 である。f90 を使うときには Makefile で FC=f90 と指定すればよい。) (5) f90 + Hbook + C++ の組合わせを利用するときは、リンク時に -L/lib/pa1.1 を指定する。
C++ コンパイラーが付ける名前は +i オプションを付けてコンパイルすると、 C++ から C のソースが作成されるので、名前がわかる。C++ では引数の種類や 数により、外部手続名が変わってくるので注意すること。
また、C++ 環境の初期化をするために、C++ のルーチンが呼ばれる前に、 _cxx_main(); を呼ぶ。
C++ の関数を使って Minuit を行う例を下に示す。メインはC である。 minuitfunc_ のなかで、minuitcpp という関数をminuitcpp__FPiPdN22N21という 名前で呼びだしていることに注意すること。
/************************************************** ** File name : minuitmain.c ** Main routine written by C */ extern void minuitfunc_(); main() { int ival ; hf_fint((char *)NULL); _cxx_main(); minuit_(minuitfunc_, ival); } /************************************************** ** File name : minuitfunc.c ** Minuit function written by C ** calls C++ routine */ void minuitfunc_( int *npar, double grad[], double *fval, double xvar[], int *iflag, int *futil) { minuitcpp__FPiPdN22N21(npar, grad, fval, xvar, iflag, futil); return; } // ************************************************** // File name : minuitcpp.C // C++ routine for minuit unction. // #include#include "FitFunc.h" FitFunc f; void minuitcpp(int *npar, double grad[], double *fval, double xvar[], int *iflag, int *futil) { if( *iflag == 1 ) { f.LoadData(); } f.Chisq(npar, grad, fval, xvar); if( *iflag == 3 ) { f.Term(npar, grad, fval, xvar); } } // ************************************************** // File name: FitFunc.h // Fit Function for Minuit. // #ifndef _FITFUNC_ #define _FITFUNC_ #define MAXDATA 50 struct FitFunc{ int nd ; // number of data; float x[MAXDATA]; FitFunc(); void LoadData(); void Chisq(int *npar, double grad[], double *fval, double xvar[]); void Term(int *npar, double grad[], double *fval, double xvar[]); }; #endif
////////////////////////////////////////////////////////// // C++ の main ////////////////////////////////////////////////////////// #includeextern "C" { extern void fsub_(int *i); extern int hf_fint(char *c); // COMMON/fcom/ibuf(maxbuf), jbuf(maxbuf) typedef struct { int ibuf[100]; int jbuf[100]; } COMMON_fcom; // COMMON 内での変数の並を示す構造体 }; COMMON_fcom fcom_; // COMMON 変数名を定義する。 main() { hf_fint((char *)NULL); // Fortran 環境の初期化 int i; i=10; fsub_(&i); // Subroutine で変数に値を設定して、読み出す。 printf(" fcom.ibuf[1]=%d\n",fcom_.ibuf[0]); for(int j=90;j<=100;j++){ fcom_.jbuf[j-1]=j*j; } i=-1; fsub_(&i); // C++ で設定した値を Fortran で読み出す。 } CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC C Fortran subrou;ne CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC subroutine fsub(id) parameter (maxbuf=100) common /fcom/ibuf(maxbuf), jbuf(maxbuf) if( id .gt. 0 ) then do 100 i=1, maxbuf ibuf(i)=id 100 continue print *,id,' was set in the array ibuf in /fcom/' else do 200 i=maxbuf-10, maxbuf print *,' jbuf(',i,')=',jbuf(i) 200 continue endif return end
////////////////////////////////////////////////////////// // C++ source ////////////////////////////////////////////////////////// extern "C" { extern void callf_(void *addr); // Prototype of fortran subroutine }; MyClass *gMyClass ; // Pointer to my C++ class double myfunc(double x[]); // Protorype for external function double myfunc(double x[]) { return gMyClass->Func(x); // Call C++ function and return result. } MyClass::MyClass() { gMyClass=this; // Remember pointer to this object } double MyClass::Func(double x[]) { double val=x[0]*x[0]; // Calculate function value and return val; // return } void MyClass::Main() { int iflag=0; callf_(myfunc, &iflag); } /* c MyClass::Main() and myfunc are equivalent to the following fortran program subroutine main external myfunc iflag = 0 call callf(myfunc, iflag) return end real*8 function myfunc(x) implicit real*8 (a-h,o-z) real*8 x(*) myfunc=x(1)*x(1) return end */ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC C Fortran subroutine CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC subroutine callf(func, iflag) implicit real*a (a-h,o-z) real*8 da(20), db(10) if( iflag .eq. 0 ) then x=func(da) else x=func(db) endif return end