Fortran と C の混合プログラミング

初版   1999.3.5
最終修正 2000.1.26

ここでのお話は Unix ( FreeBSD , Linux , Sun OS ) でのお話です。

1. 関数名の付き方

C の関数はコンパイルされると 関数名の左に _ ( アンダーバー ) を付けた名前がつきます。 次のような例を実行してみて下さい。

----------- csub.c の内容 --------- csub(){} ---------------------------------- % cc -c csub.c % nm csub.o

一方、Fortran では関数名の両側に _ をつけます。次のような 例を実行してみて下さい。

----------- ffub.f の内容 --------- subroutine fsub() return end subroutine fsub_2() return end ---------------------------------- % f77 -c fsub.f % nm fsub.o

ですから、C から fortran のサブルーチンを呼ぶ場合は、 あらかじめサブルーチン名の右に _ を付けておけばよろしい。 また、fortran から呼ばれる C の関数は右側に _ を付けた 名前にしておきます。

アンダースコアを含む関数名は右側に _ が 2 つ付く処理系と 1 つしか付かない処理系があります。SunOS 4.x の純正 Fortran や古い News-OS の Fortran は 1 つしか付かないのに対して、 内部で f2c を使う FreeBSD の f77 や g77 は 2 つ 付けます。自分の処理系がどちらなのかは nm コマンドで 確認して下さい。


2. 引数の渡し方

C には関数への引数の渡し方として、値渡しと参照渡しの 2 種類が ありますが、Fortran は参照渡しのみです。ですから、常に 参照渡しを使うようにして下さい。

文字型変数は C と Fortran では 形式が異なります。C では文字列の終端を \0 で表しますが、 Fortran では文字型変数は固定長であり、余った部分は空白が 入ります。つまり、

character*5 cha cha = '123' <--- (1) cha = '123 ' <----(2)

の (1) は (2) と同じことです。 サブルーチンをコールするときは、引数として、文字列の先頭アドレスと 文字長 ( long 型 ) を渡します。


3. C から Fortran を呼ぶ例

以上のルールを理解すれば、次のように書けます。但し、

ことに注意して下さい。まずは、C から Fortran を呼ぶ例を示します。

-------------------- main.c ここから --------------------- main(){ int i=3,len; float f=5; char str[10]; long l=10; strcpy(str,"abcd"); len = strlen(str); cha[len] = ' '; <-- "abcd" の直後のヌルコードを空白で置換 fsub_(&i,&f,cha,l); <-- 文字型変数の固定長が必要 <-- サブルーチン名の後に _ が必要 } --------------------- main.c ここまで ----------------- --------------------- sub.f ここから ------------------- subroutine fsub(i,f,cha) character*(*) cha write(6,*) 'length : ',len(cha) <--- 10 が表示される write(6,*) i,f,cha <--- 3 , 5. , abcd が表示される return end ---------------------- sub.f ここまで -------------------- % f77 main.c sub.f

このように、

に注意すればよいことが分かります。


4. fortran から C を呼ぶ例

C には system() という便利な関数があります。fortran でも

call system('a2ps text.txt | lpr ')

などとできる関数があれば便利です。このような fortran から 呼べる system 関数を作ってみました。

------------------ system.c ここから ---------------- #include <stdio.h> #include <stdlib.h> #define BUFLEN 400 /* f2c は Conventional C でもコンパイルできるように、 Fortran の Subroutine は int 型の関数で表す。 以下の system_ 関数は、それとの整合性を取り、Conventional C でもコンパイルできるような形で記述してある g77 でコンパイルするとどうなるかは分からない。たぶん、大丈夫 だとは思うが・・・ */ system_(str,len) char str[]; long len; { int i; char str2[BUFLEN]; /* 入力変数のうち、空白でない文字が何文字あるか調べる 文字型定数の場合は、文字数 = len である */ i = len - 1; for(;;){ if ( i < 0 ){ i = 0 ; break; } if ( str[i] != ' ' ) { i++; break; } i--; } /* その文字数だけ str2 にコピーし、終端記号を加える */ if ( i >= BUFLEN ){ fprintf(stderr,"Error in system\n"); exit(1); } strncpy(str2,str,i); str2[i] = '\0'; /* system 文の実行 */ printf("system(\"%s\")\n",str2); system(str2); } ----------------- system.c ここまで ---------------

もし、system 関数の返り値が欲しい時 ( Ctrl-C を押した時を検出 したい ) は、

system_(str,iret,len) char str[]; int *iret; long len; ...... ここは同じ ......... *iret = system(str2) }

として、fortran からは

call system('ls',iret)

のようにすればよろしい。

如何でしたでしょうか。このように考えると、C と fortran は同じに 見えてきます。ですから、適材適所の考え方で C と fortran の混合 プログラミングをして下さい。

混合プログラミングのより詳しい情報 ( common 文へのアクセスとか ) が 載っている本をどこかで見た覚えがあるのですが・・・ 書名は忘れて しまいました。