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
このように、
- 呼ぶ fortran 関数の右に _ を付ける
- 引数はアドレス渡し
- 文字型変数の場合は全ての引数の後に、文字型変数の長さを付け加える
に注意すればよいことが分かります。
4. fortran から C を呼ぶ例
C には system() という便利な関数があります。fortran でも
call system('a2ps text.txt | lpr ')
などとできる関数があれば便利です。このような fortran から
呼べる system 関数を作ってみました。
------------------ system.c ここから ----------------
#include
#include
#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 文へのアクセスとか ) が
載っている本をどこかで見た覚えがあるのですが・・・ 書名は忘れて
しまいました。