c++ から fortran サブルーチンを呼ぶには?

(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 を指定する。

Hbook を C++ から使用する例はここ

Fortran 又は C から C++ を呼ぶには

Fortran では外部手続名の最後にアンダースコア(_)が付けられているが、 C++ ではアンダースコアーが後ろにつかない名前が自動的に作成されるので、 Fortran から直接C++ のルーチンを呼ぶことはできない。C を経由して呼び出すことが必要。

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++ から fortran の COMMON を参照するには?

Fortranの COMMON にC++ のルーチンからアクセスする例、を示す。
//////////////////////////////////////////////////////////
//  C++ の main 
//////////////////////////////////////////////////////////
#include 

extern "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

EXTERNAL 関数を使ったfortran プログラムをC++ から呼び出すには?

クラスの中のメンバー関数は、外部参照名が定まっていないので、 C++ から fortran プログラムを呼び出す際に、そのメンバー関数の アドレスを直接書くことはできない。そこで、下の例題プログラムの 様にラップしてから呼び出すようにする。
//////////////////////////////////////////////////////////
//  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	

宮本彰也:最終更新日1998年9月9日