(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