これは、2000/06/26 の MkLinux/LinuxPPC な生活に書いたものである。Fortran と C++ と言うと和洋折衷というより、古代料理と現代グルメ料理の組み合わせと言った方が適切かもしれない。いずれにせよ、Fortran の遺産はまだまだ大きいのでこれを活用しようと言うわけである。実際、縄文食は健康的だがグルメは体に悪いからというわけでもなかろうが、Fortran にこだわり続ける人がこの業界にも結構いる。
実際、BASES/SPRING のヒストグラムパッケージが C++ になってしまったので、これが必須。以下に例を示す。
FORTRAN は例えば以下のようにヒストグラムをフィルするサブルーチン xhfill を呼ぶ。
subrouitine func(x)ここで、x はフィルする値、w は重みである。この xhfill の実体を C++ で書かれた JSFBases クラスのメンバー関数(JSFBases::H1Fill)にしたいわけである。
implicit real*8 (a-h,o-z)
external xhfill
.........
call xhfill('h01', x, w)
.........
return
JSFBases *bso; // これは H1Fill をメンバー関数とする JSFBases オブジェクトへのポインターFORTRAN 関数名にはアンダースコアーがつけられること、引数が全て値でなくアドレスわたしであること、そして FORTRAN の文字列の扱いの特殊性に注意(FORTRAN では文字列はヌルターミネートされておらず、そのかわりに文字列の長さを、FORTRAN では見えない引数でわたす。従って C または C++ にその文字列をわたす際にはヌルターミネートしてから、その長さといっしょにわたす必要がある)。
extern "C" { // これでシンボル名がマングルされないので、FORTRAN から見える
void xhfill_(char *t, double *x, double *w, int len) // xhfill の後のアンダースコアー、
{ // 文字列の長さを保持する引数 len に注意。
char tmp[1024]; // また、引数は全てアドレスわたしである。
int i;
for (i=0; i<len; i++) tmp[i] = t[i];
tmp[len] = '\0'; // FORTRAN の文字列はヌルターミネートされていない。
bso->H1Fill(tmp,*x,*w); // 実行時、bso は確定しているのでメンバー関数が呼び出せる。
}
}
jSFBases::JSFBases(......) : .....
{
.....
bso = this;
.....
}
のようにセットする。スタティック関数なら bso->H1Fill(tmp,*x,*w) のようにポインターを使うのでなく、JSFBases::H1Fill(tmp,*x,*w)
のように書けばよい。
これは、上の場合のノウハウの応用である。例えば
subroutine subfort(i,x,str1,array,str2)なる FORTRAN 関数は、
integer*4 i
real*4 x
character*(*) str1, str2
......
return
end
extern "C" {などとしておけば良い。もちろん、これを C++ から呼ぶ際にはアドレスわたしであることに注意し、len1 と len2 もセットして呼ばねばならない。
extern void subfort_(int *i, float *x, char *str1, float array[],
char *str2, int len1, int len2);
......
}
int i = 0;
float x =1.;
float array[] = {0., 1., 2.};
char *str1 = ".....";
char *str2 = ".....";
......
subfort_(&i, &x, str1, array, str2, strlen(str1), strlen(str2));
のような感じ。
例えば、次のような FORTRAN の COMMON にアクセスしたい場合。
common /fcom/ i, x, y, a(100)まず
integer*4 i
real*4 x, y, a
extern "C" {などと宣言し、
typedef struct {
int i;
float x;
float y;
float a[100];
} COMMON_fcom;
}
extern COMMON_fcom fcom_;後は、C++ のプログラムの中で
fcom_.i = 1;などとすればよい。これで、FORTRAN の配列要素:a(11) が変更される。FORTRAN 配列は1から始まる点に注意。
fcom_.a[10] = 0.5;
float x = fcom_.x;