ほとんどの C と Fortran のインタフェースでは、次に示すことを正しく理解しておく必要があります。
関数とサブルーチンの定義と呼び出し
データ型の互換性
引数の参照渡しと値渡し
引数の順番
手続き名 - 大文字、小文字、または末尾に下線 (_) 付き
正しいライブラリ参照をリンカーに渡す
また、一部の C と Fortran のインタフェースでは、次に示すことを正しく理解しておく必要があります。
配列の添字付けと順序
ファイル記述子と stdio
ファイルのアクセス権
「関数」という言葉の意味は、C と Fortran では異なります。 状況によって、どちらの意味で解釈するかが重要です。
Fortran では、関数とは値を返すものであり、値を返さないものはサブルーチンといいます。
Fortran ルーチンから C 関数を呼び出す場合
値を返す C の関数は、Fortran から関数として呼び出します。
値を返さない C の関数は、Fortran からサブルーチンとして呼び出します。
C 関数から Fortran 副プログラムを呼び出す場合
Fortran 副プログラムが関数の場合は、C から、対応するデータ型を返す関数として呼び出します。
Fortran 副プログラムがサブルーチンの場合は、C から int (これは Fortran の INTEGER*4 に対応する) または void を返す関数として呼び出します。Fortran のサブルーチンが選択戻りをする場合は 1 つの値が戻されます。Fortran のサブルーチンが選択戻りをする場合は 1 つの値が戻されます。 この場合、RETURN 文にある式の値です。RETURN 文に式がない場合、または SUBROUTINE 文で選択戻りが 宣言されている場合、ゼロが戻されます。
表 11–2 では、Fortran 95 のデータ型と C のデータ型のデータサイズとデフォルトの境界整列を比較しています。ここでは、境界に影響したり、適用されるデフォルトのデータサイズを昇格させたりするコンパイルオプションを指定しないものとします。次の点に注意してください。
C のデータ型 int、long int、long は、32 ビット環境では等価です (4 バイト)。しかし、64 ビット環境では long とポインタは 8 バイトになります。これは LP64 データモデルと呼ばれます。
64 ビット環境で -m64 および、これに相当するオプションを使用してコンパイルすると、REAL*16 と COMPLEX*32 は 16 バイト境界に整列されます。
4/8 と示されている境界整列は、デフォルトでは 8 バイト境界を意味しますが、共通ブロックでは 4 バイト境界を意味しています。共通ブロックでのデフォルトの最大境界整列は 4 バイトです。4/8/16 は、-m64 オプションを使用してコンパイルしたとき 16 バイト境界に整列されることを意味します。
REAL(KIND=16)、REAL*16、COMPLEX(KIND=16)、および COMPLEX*32 は SPARC プラットフォームでのみ使用できます。
配列と構造体の要素および欄はそれぞれ互換性がなければいけません。
配列、文字列、構造体を値で渡すことはできません。
呼び出し側で %VAL(arg) を使用すると、Fortran 95 ルーチンから C ルーチンに値で引数を渡すことができます。C から Fortran 95 に値で引数を渡すことはできますが、Fortran ルーチンに、VALUE 属性とともに仮引数を宣言している明示的なインタフェースブロックがあることが条件となります。
数値シーケンス型の要素は共通ブロックと同様に整列され、-aligncommon オプションによっても制御されます。 数値シーケンス型は、すべての要素がデフォルトの整数型かデフォルトの実数型、倍精度実数型、デフォルトの複素数型、デフォルトの論理型のいずれかで、ポインタではない連続型です。
QUAD 変数を除き、数値シーケンス型ではないデータ型の要素は、たいていの場合、自然整列になります。4 倍精度の変数の場合、境界整列は 32 ビットと 64 ビットの SPARC プラットフォームで異なります。
VAX 構造体の要素、および BIND(C) 属性で定義されたデータ型は、どのプラットフォームでも C の構造体と同じ境界整列になります。
Fortran 95 のデータ型 |
C のデータ型 |
サイズ |
境界 |
|
---|---|---|---|---|
BYTE x |
char x |
1 |
1 |
|
CHARACTER x |
unsigned char x ; |
1 |
1 |
|
CHARACTER (LEN=n) x |
unsigned char x[n] ; |
n |
1 |
|
COMPLEX x |
struct {float r,i;} x; |
8 |
4 |
|
COMPLEX (KIND=4) x COMPLEX (KIND=8) x COMPLEX (KIND=16) x (SPARC) |
struct {float r,i;} x; struct {double dr,di;} x; struct {long double, dr,di;} x; |
8 16 32 |
4 4/8 4/8/16 |
|
DOUBLE COMPLEX x |
struct {double dr, di;} x; |
16 |
4/8 |
|
DOUBLE PRECISION x |
double x ; |
8 |
4 |
|
REAL x |
float x ; |
4 |
4 |
|
REAL (KIND=4) x REAL (KIND=8) x REAL (KIND=16) x (SPARC) |
float x ; double x ; long double x ; |
4 8 16 |
4 4/8 4/8/16 |
|
INTEGER x |
int x ; |
4 |
4 |
|
INTEGER (KIND=1) x INTEGER (KIND=2) x INTEGER (KIND=4) x INTEGER (KIND=8) x |
signed char x ; short x ; int x ; long long int x; |
1 2 4 8 |
4 4 4 4 |
|
LOGICAL x |
int x ; |
4 |
4 |
|
LOGICAL (KIND=1) x LOGICAL (KIND=2) x LOGICAL (KIND=4) x LOGICAL (KIND=8) x |
signed char x ; short x ; int x ; long long int x; |
1 2 4 8 |
4 4 4 4 |
C と Fortran では、字種 (大文字/小文字) に関する扱いが異なります。
C では字種に意味があり、大文字と小文字を別のものとして扱います。
Fortran では、デフォルトでは字種に意味がありません。
f95 のデフォルトでは、副プログラム名を小文字に変換して、字種を無視します。 つまり、文字列定数の中を除き、すべての大文字を小文字に変換します。
大文字と小文字に関する問題には、一般に次のような 2 つの解決策があります。
C の副プログラムで、C の関数名をすべて小文字にします。
-U オプションを付けて Fortran プログラムをコンパイルします。 これは、コンパイラに、関数名と副プログラム名における既存の字種の区別をそのまま保持させるオプションです。
前述の 2 つの解決策のどちらか 1 つを使用してください。 両方を使用してはいけません。
この章の例のほとんどは、C の関数名に小文字だけを使用しています。f95-U コンパイラオプションは使用していません。
Fortran コンパイラは、通常、入口定義と呼び出しの両方に現れる副プログラムの名前に下線 (_) を追加します。これによって、ユーザー割り当て名が同じである C の手続きや外部変数と区別します。Fortran ライブラリのほとんどすべての手続き名には、ユーザーが割り当てるサブルーチンとの競合を減らすため、先頭に 2 つの下線が付けられています。
下線に関する問題には、一般に次の 3 つの解決策があります。
C の関数で、下線を追加して関数名を変更する。
f95 の -ext_names オプションを使用して、下線を使用しないで外部名への参照をコンパイルする。
これらの中のいずれか 1 つを使用してください。
この章の例は、BIND(C) 属性宣言を使用して、下線をなくしています。 BIND(C) は、C の外部関数が Fortran から呼び出し可能なこと、また Fortran ルーチンが引数として C から呼び出し可能なことを宣言します。Fortran は、通常、外部名に対して行うようには下線を付加しません。 BIND(C) は、そうした参照を含むそれぞれの副プログラム内で使用する必要があります。使用規則は次のとおりです。
FUNCTION ABC EXTERNAL XYZ BIND(C) ABC, XYZ |
この例では、XYZ が外部 C 関数であることばかりでなく、Fortran の呼び出し側の ABC を C 関数から呼び出し可能であると宣言しています。BIND(C) を使用すると、C の関数の方で名前に下線を追加する必要はありません。
一般的には、Fortran ルーチンは引数を参照で渡します。呼び出し時に、非標準関数の %VAL() に引数を入れると、呼び出し元のルーチンはその引数を値で渡します。
Fortran 95 で引数を値で渡す場合の標準的な方法は、VALUE 属性と INTERFACE ブロックを使用する方法です。「11.4 データ引数の値渡し」を参照してください。
一般的には、C は引数を値で渡します。引数の前にアンパサンド記号 (&) を付けた場合は、C はその引数を、ポインタを使用して参照で渡します。配列と文字列に関しては、C でも常に参照で渡します。
文字列の引数の場合を除くと、Fortran と C は引数を同じ順序で渡します。ただし、各文字列引数については、Fortran ではさらに文字列の長さを示す引数も渡します。文字列長は、値で渡される C の long int の量と同じです。
引数の順序は次のとおりです。
各引数 (データであっても関数であっても) のアドレス
各文字引数に対する long int (文字列長の並び全体は、ほかの引数の並び全体のあとにきます)
例:
Fortran コードの一部 |
対応する C のコード |
||
---|---|---|---|
|
|
配列の添字付けと順番については Fortran と C とでは異なります。
C の配列は常にゼロから始まりますが、Fortran の配列はデフォルトでは 1 から始まります。この問題には、次のような 2 つの解決策があります。
前述の例のように、Fortran のデフォルトを使用します。このときは、Fortran の B(2) 要素は C の b[1] 要素と同義になります。
Fortran の配列 B を B(0) で始まるように指定します。
INTEGER B(0:2) |
このときは、Fortran の要素 B(1) が C の b[1] 要素と同義になります。
Fortran の配列は列主導の順番で、A(3,2) のように格納されます。
A(1,1) A(2,1) A(3,1) A(1,2) A(2,2) A(3,2) |
C の配列は行主導の順番で、A[3][2] のように格納されます。
A[0][0] A[0][1] A[1][0] A[1][1] A[2][0] A[2][1] |
1 次元の配列では、これによって問題は生じません。しかし、多次元の配列では、すべての参照と宣言における添字の順番と使用法に気をつけてください。 なんらかの調整が必要になります。
たとえば、行列操作の一部を C で行い、残りを Fortran で行うのは混乱が生じる可能性があります。一方の言語で全体の配列をルーチンに渡し、そのルーチン内ですべての行列操作を実行すれば、混乱を避けることができます。
Fortran の入出力チャネルは、装置番号で表されます。プラットフォームとして使用している SunOS オペレーティングシステムは、装置番号ではなく、ファイル記述子を扱います。Fortran の実行時のシステムが装置番号からファイル記述子に変換するので、ほとんどの Fortran プログラムはファイル記述子を認識する必要はありません。
C プログラムの多くは、標準入出力 (stdio) と呼ばれるサブルーチンセットを使用しています。Fortran の入出力関数の多くは標準入出力を使用しており、これはオペレーティングシステムの入出力呼び出しを使用しています。このような入出力システムの特性の一部を次の表に示します。
表 11–2 Fortran と C の入出力の比較
|
Fortran 装置 |
標準入出力のファイルポインタ |
ファイル記述子 |
---|---|---|---|
ファイルを開く |
読み書き用に開く |
読み取り用、書き込み用、読み書き両用、または追加用に開く。open(2) 参照 |
読み取り用、書き込み用、または読み書き両用に開く。 |
属性 |
書式付き、書式なし |
常に書式なし、ただし、書式解釈ルーチンによる読み書きは可能。 |
常に書式なし |
探査 |
直接、順番 |
物理ファイルの表現が直接探査の場合は直接探査、ただし、常に順番に読み取り可。 |
物理ファイルの表現が直接探査の場合は直接探査、ただし、常に順番に読み取り可。 |
構造 |
レコード |
バイトストリーム |
バイトストリーム |
形式 |
任意の負でない 0 から 2147483647 までの整数 |
ユーザーのアドレス空間における構造体へのポインタ |
0 から 1023 までの整数 |
適切な Fortran および C ライブラリをリンクするためには、f95 コマンドを使用して、リンカーを起動します。
例 1: コンパイラを使用してリンクします。
demo% cc -c someCroutine.c demo% f95 theF95routine.f someCroutine.o <- このコマンド行でリンクを実行 demo% a.out 4.0 4.5 8.0 9.0 demo% |