Fortran プログラミングガイド ホーム目次前ページへ次ページへ索引


第 11 章

C と Fortran のインタフェース

この章では、Fortran と C との相互運用性の問題を取り上げます。

Sun FORTRAN 77、Fortran 95、および C コンパイラに固有な問題だけを扱います。


注 - Sun FORTRAN 77 と Fortran 95 に共通の内容は、FORTRAN 77 を使用して説明します。

互換性について

ほとんどの C と Fortran のインタフェースでは、次に示すことを正しく理解しておく必要があります。

また、一部の C と Fortran のインタフェースでは、次に示すことを正しく理解しておく必要があります。

関数とサブルーチン

「関数」という言葉の意味は、C と Fortran では異なります。状況によって、どちらの意味で解釈するかが重要です。

Fortran ルーチンから C 関数を呼び出す場合

C 関数から Fortran 副プログラムを呼び出す場合

データ型の互換性

表 11-1表 11-2 で、FORTRAN 77 と Fortran 95 のデータ型のサイズとデフォルトの境界整列を示しています。次の点に注意してください。

FORTRAN 77 とC のデータ型

表 11-1 に、FORTRAN 77 のデータ型のサイズと境界を示します。ここでは、境界に影響したり、適用されるデフォルトのデータサイズを昇格させたりするコンパイルオプションを指定しないものとします。(『FORTRAN 77 言語リファレンス』も参照)

表 11-1   データサイズと境界 - 参照渡し (f77cc
FORTRAN 77 のデータ型 C のデータ型 サイズ デフォルトの境界 SPARC x86
BYTE X
CHARACTER X
CHARACTER*n X
char x
unsigned char x
unsigned char x[n]
1
1
n
1 
1 
1 
1
1
1
COMPLEX X
COMPLEX*8 X
DOUBLE COMPLEX X
COMPLEX*16 X
COMPLEX*32 X 
struct {float r,i;} x;
struct {float r,i;} x;
struct {double dr,di;}x;
struct {double dr,di;}x;
struct {long double dr,di;} x;
8
8
16
16
32
4 
4 
4/8 
4/8
4/8/16
4
4
4
4
--
DOUBLE PRECISION X
REAL X
REAL*4 X
REAL*8 X
REAL*16 X 
double x
float x
float x
double x
long double x
8
4
4
8
16
4/8 
4 
4 
4/8
4/8/16
4
4
4
4
--
INTEGER X
INTEGER*2 X
INTEGER*4 X
INTEGER*8 X
int x
short x
int x
long long int x
4
2
4
8
4 
2 
4 
4
4
2
4
4
LOGICAL X
LOGICAL*1 X
LOGICAL*2 X
LOGICAL*4 X
LOGICAL*8 X
int x
char x
short x
int x
long long int x
4
1
2
4
8
4 
1 
2 
4 
4
4
1
2
4
4


SPARC: Fortran 95 と C のデータ型

次の表に、Fortran 95 と C のデータ型の比較を示します。

表 11-2   データサイズと境界 - 参照渡し (f95cc) (SPARC のみ)  
Fortran 90 のデータ型 C のデータ型 サイズ
バイト
境界
バイト
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
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
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 longint 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 では、字種 (大文字/小文字) に関する扱いが異なっています。

f77f95 のデフォルトでは、副プログラム名を小文字に変換して、字種を無視します。実際には、文字列定数の中を除き、すべての大文字を小文字に変換します。

大文字と小文字に関する問題には、一般に次のような 2 つの解決策があります。

上記 2 つの解決策のどちらか 1 つを使用してください。両方を使用してはなりません。

この章の例のほとんどは、C の関数名に小文字を使用しています。f77-U コンパイラオプションは使用していません。

ルーチン名の下線

Fortran コンパイラは通常、入口定義と呼び出しの中の両方に現れる副プログラムの名前に下線 (_) を追加します。これによって、ユーザー割り当て名が同じである C の手続きや外部変数と区別します。名前がちょうど 32 文字である場合は、下線は追加されません。Fortran ライブラリの手続き名にはすべて、ユーザーが割り当てるサブルーチンとの競合を減らすため、先頭に 2 つの下線が付けられています。

下線に関する問題には、一般に次の 3 つの解決策があります。

これらの中のいずれか 1 つを使用してください。

この章の例は、C() コンパイラプラグマを使用して、下線を無くしています。C() プラグマ指令は、外部関数の名前を引数として取ります。これは、このような関数が C 言語で書かれていることを示します。このため、Fortran コンパイラは、通常は外部名に対して追加する下線を、当該の関数名には追加しません。特定の関数に対する C() 指令は、その関数への最初の参照より前に指定しなければなりません。また、そのような参照を含む副プログラムごとに指定しなければなりません。使用規則は次のとおりです。

    EXTERNAL ABC, XYZ	!$PRAGMA C( ABC, XYZ ) 

このプラグマを使用する場合は、C の関数のほうでは名前に下線を追加してはなりません。PRAGMA 指令については、『Fortran ユーザーズガイド』で説明しています。

引数の参照渡しと値渡し

一般的には、Fortran ルーチンは引数を参照で渡します。呼び出し時に、引数を f77 および f95 の非標準関数の %VAL() で囲んだ場合は、呼び出し元のルーチンはその引数を値で渡します。

一般的には、C は引数を値で渡します。引数の前にアンパサンド記号 (&) を付けた場合は、C はその引数をポインタを使用して参照で渡します。配列と文字列に関しては、C でも常に参照で渡します。

引数と順番

文字列の引数の場合を除くと、Fortran と C は引数を同じ順序で渡します。ただし、各文字列引数については、Fortran ではさらに文字列の長さを示す引数も渡します。文字列長は、値で渡される C の long int の量と同じです。

引数の順番は次のとおりです。

例 :

Fortran コードの一部
対応する C のコード
    CHARACTER*7 S
    INTEGER B(3)
     ...
    CALL SAM( S, B(2) )
    char s[7];
    long b[3];
      ...
    sam_( s, &b[1], 7L ) ;


配列の添字付けと順番

配列の添字付けと順番については Fortran と C とでは異なります。

配列の添字付け

C の配列は常にゼロから始まりますが、Fortran の配列はデフォルトでは 1 から始まります。この問題には、次のような 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 次元配列では問題ありません。2 次元以上の配列では、すべての参照と宣言における添字の順番と使用法に気をつけてください。なんらかの調整が必要になります。

たとえば、行列操作の一部を C で行い、残りを Fortran で行うのは混乱が生じる可能性があります。一方の言語で全体の配列をルーチンに渡し、そのルーチン内ですべての行列操作を実行すれば、混乱を避けることができます。

ファイル記述子と stdio

Fortran の入出力チャネルは、装置番号で表されます。入出力システムは、装置番号ではなく、ファイル記述子を扱います。Fortran の実行時のシステムが装置番号からファイル記述子に変換するので、ほとんどの Fortran プログラムはファイル記述子を認識する必要はありません。

C プログラムの多くは、標準入出力 (stdio) と呼ばれるサブルーチンセットを使用しています。Fortran の入出力関数の多くは標準入出力を使用しており、これはオペレーティングシステムの入出力呼び出しを使用しています。このような入出力システムの特性の一部を表 11-3 に示します。

表 11-3   Fortran と C の入出力の比較

Fortran 装置 標準入出力のファイルポインタ ファイル記述子
ファイルを開く 読み書き用に開く 読み取り用に開く、書き込み用に開く、読み書き両用に開く、追加用に開く。OPEN(2) 参照 読み取り用に開く、書き込み用に開く、読み書き両用に開く。
属性 書式付き、書式なし 常に書式なし、ただし、書式解釈ルーチンによる読み書きは可能 常に書式なし
探査 直接、順番 物理ファイルの表現が直接探査の場合は直接探査、ただし、常に順番に読み取り可。 物理ファイルの表現が直接探査の場合は直接探査、ただし、常に順番に読み取り可。
構造 記録 バイトストリーム バイトストリーム
形式 任意の負でない 0 から 2147483647 までの整数 ユーザーのアドレス空間における構造体へのポインタ 0 から 1023 までの整数


ファイルのアクセス権

C プログラマは一般的に、入力ファイルを読み取り用に開き、出力ファイルを書き込み用または読み書き両用に開きます。f95 プログラムはファイルを READONLY (読み取り専用) としてOPEN (開く) できますが、READWRITE='READ''WRITE''READWRITE' でファイルを開くこともします。f90READWRITE 指示子はサポートしますが、READONLY はサポートしません。

Fortran は、まず読み書き両用として、それが不可能なときは個別の目的のものとして、可能な限りのアクセス権でファイルを開こうとします。

これは透過的に行われるので、ユーザーが意識するのは READ、WRITE、ENDFILE の操作を実行しようとしたがアクセス査権がなかった場合のみです。この一般的な自在性の中で磁気テープの操作は例外です。これは、ファイルに書き込み権があっても、テープに書き込みリングが付いていなければ書き込めないからです。

ライブラリと f77 または f95 コマンドでのリンク

適切な Fortran および C ライブラリをリンクするためには、f77 または f90 コマンドを使用して、リンカーを起動してください。

例 1 : f77 でリンクします。

demo% cc -c RetCmplxmain.c 
demo% f77 RetCmplx.f RetCmplxmain.o  このコマンド行でリンクしている
demo% a.out 
 4.0 4.5 
 8.0 9.0 
demo%

Fortran 初期化ルーチン

f77f95 によりコンパイルされた主プログラムでは、プログラム起動時にライブラリのダミー初期化ルーチン f77_init または f90_init を呼び出します。ライブラリのルーチンは、ダミーであり、何も処理しません。コンパイラにより生成される呼び出しでは、プログラムの引数と環境へのポインタが渡されます。これらの呼び出しにより、プログラマが各自の C 言語ルーチンでプログラムの起動前に独自の方法でプログラムを初期化するときに使用できるソフトウェアのフックが提供されます。

このような初期化ルーチンの使用法の一つに、国際化された Fortran プログラムに対して setlocale を呼び出す方法があります。Setlocale は、libc が静的にリンクされている場合機能しないので、libc に動的にリンクされる Fortran プログラムだけが国際化できます。

ライブラリの init ルーチンのソースコードは、次のとおりです。

void f77_init(int *argc_ptr, char ***argv_ptr, char ***envp_ptr) {}
void f90_init(int *argc_ptr, char ***argv_ptr, Char ***envp_ptr) {}

ルーチン f77_init は、f77 主プログラムにより呼び出されます。ルーチン f90_init は、f95 主プログラムにより呼び出されます。各引数には、argc のアドレス、argv のアドレス、envp のアドレスが設定されます。

データ引数の参照渡し

Fortran ルーチンと C 手続きとの間でデータを渡す標準的な方法は、参照渡しです。C の手続きから見ると、Fortran の副プログラムまたは関数呼び出しは、すべての引数をポインタで表す手続き呼び出しのようになります。唯一異なる点は、Fortran が文字列と関数を引数としてあつかう方法と、CHARACTER*n 関数の戻り値としてあつかう方法です。

単純なデータ型

複素数データ

64 ビット環境で、-xarch=v9 でコンパイルすると、COMPLEX 値がレジスタに戻されます。

文字列

C と Fortran ルーチンとの間で文字列を渡すことは推奨できません。これは、標準的なインタフェースがないからです。ただし、次を考慮してください。

次の例で、文字列を引数とする Fortran 呼び出しを、対応する C のコードと共に示します。

表 11-6   CHARACTER 文字列を渡す
Fortran が C を呼び出す C に対応する Fortran のコード
  CHARACTER*7 S
  INTEGER B(3)
 ...
  CALL CSTRNG( S, B(2) )
 ...
  char s[7];
  int b[3];
  ...
  cstrng_( s, &b[1], 7L );
  ...


文字列の長さが呼び出されたルーチンで必要なければ、追加の引数は無視されます。ただし、Fortran では C のように明示的なヌル文字で文字列を自動的に終了させません。これは、呼び出し側のプログラムで追加する必要があります。

1 次元配列

2 次元配列

構造体

ポインタ

データ引数の値渡し

値による呼び出しは、FORTRAN 77 で単純型データでだけ利用でき、また、C のルーチンを呼び出す Fortran ルーチンによってだけ利用できます。C のルーチンが Fortran ルーチンを呼び出して、値により引数を渡す方法はありません。配列、文字列、構造体を値で渡すことはできません。参照により渡すようにしてください。

次の例では、Fortran ルーチンが値により x を、参照により y を渡しています。C のルーチンは xy を増分しましたが、y だけが変更されます。

表 11-12   単純型データ引数を値により渡す - Fortran 77 が C を呼び出す
Fortran 77 がC を呼び出す
  REAL x, y
  x = 1.
  y = 0.
  PRINT *, x,y
  CALL value( %VAL(x), y)
  PRINT *, x,y
  END
-----------------------------------------
------------------
void value_( float x, float *y)
{
  printf("%f, %f\n",x,*y);
  x = x + 1.;
  *y = *y + 1.;
  printf("%f, %f\n",x,*y);
}
-----------------------------------------
------------------
Compiling and running produces output:
     1.00000  0.   Fortran からの x と y
1.000000, 0.000000   C からの x と y
2.000000, 1.000000  C からの新しい x と y
     1.00000  1.00000  Fortran からの新しい
                                                       x と y


値を戻す関数

BYTE (FORTRAN 77 のみ)、INTEGER、REAL、LOGICAL、DOUBLE PRECISION または REAL*16 (SPARC のみ) 型の値を戻す Fortran 関数は、互換性のある型を戻す C の関数と同義です (表 11-1表 11-2 を参照)。文字関数の戻り値には引数が 2 つ追加され、複素数関数の戻り値には引数が 1 つ追加されます。

単純型データを戻す

複素数データを戻す

64 ビット環境で、-xarch=v9 でコンパイルすると、COMPLEX 値が浮動小数点レジスタに戻されます。COMPLEXDOUBLE COMPLEX はそれぞれ %f0 と%f1 に、COMPLEX*32 は %f、%f1、%f2、%f3 に戻されます。これらのレジスタは C プログラムでは直接アクセスできないので、この場合の SPARC V9 プラットフォームでは Fortran と C 言語の間で相互操作性は実現されません。

CHARACTER 文字列を戻す

この例では、C 関数と呼び出し側の C ルーチンは、リストの最初に 2 つの引数 (結果として戻される文字列へのポインタと文字列長) が、そして、リストの最後に 1 つの追加引数 (文字列引数の長さ) が追加されています。C から呼び出された Fortran ルーチンでは最後のヌル文字を明示的に追加する必要があることに注意してください。

名前付き COMMON

Fortran の名前付き COMMON は、大域的構造体を使用して C の中で代替できます。

表 11-16   名前付き COMMON
Fortran のCOMMON 定義 C の "COMMON" 定義
 COMMON /BLOCK/ ALPHA,NUM
  ...

 extern struct block {
    float alpha;
    int num;
    };
 extern struct block block_ ;

 
 main ()
 {
  ...
  block_.alpha = 32.;
  block_.num += 1;
  ...
 }


C ルーチンにより確立された外部名は、Fortran プログラムにより作成されたブロックとリンクさせるために下線で終了しなければなりません。C 指令 #pragma pack は Fortran のときと同じ埋め込みが必要な場合があります。f77f95 の両方で、共通ブロックのデータを最大で 4 バイト境界に境界割り当てします。

Fortran と C との入出力の共有

Fortran の入出力と C の入出力を混合することは (C と Fortran ルーチンの両方から入出力呼び出しを発行すること)、推奨できません。すべて Fortran の入出力で行うか、すべて C の入出力で行うかのどちらかに統一するのが安全です。

Fortran の入出力ライブラリは、大部分が C の標準入出力ライブラリの上に実装されています。Fortran プログラムで開いた装置はすべて、標準入出力のファイル構造と対応付けられています。stdin、stdout、stderr のストリームに関しては、ファイル構造を明示的に参照する必要がなく、共有できます。

Fortran の主プログラムが入出力を行うために C を呼び出す場合、Fortran の入出力ライブラリはプログラム起動時に、装置 0、5、6 がそれぞれ stderr、stdin、stdout に接続するよう初期化されます。ファイル記述子を開いて入出力を実行する場合、C の関数は Fortran の入出力環境を考慮しなければなりません。

ただし、C の主プログラムが Fortran の副プログラムを呼び出して入出力を行う場合、装置 0、5、6 を stderr、stdin、stdout に接続する Fortran 入出力ライブラリの自動初期化が行われません。この接続は通常 Fortran の主プログラムにより行われます。Fortran 関数が通常の Fortran 主プログラム入出力初期化をせずに stderr ストリーム (装置 0) を参照しようとした場合、出力は stderr ストリームではなく、fort.0 に書き込まれます。

C の主プログラムは、プログラムの先頭で FORTRAN 77 のライブラリルーチン
f_init() を呼び出すことにより Fortran 入出力を初期化し、装置 0、5、6 を事前に接続することができます。また、必要に応じて終了時に f_exit() を呼び出すこともできます。

たとえ主プログラムが C で書かれていても、f77 でリンクするべきであることに注意してください。

選択戻り

Fortran の選択戻り機能はあまり使用されなくなっているため、移植上の問題がなければ使用しないでください。選択戻りに対応する機能は C にはありません。したがって、問題は C のルーチンが選択戻りを持つ Fortran のルーチンを呼び出す場合だけです。

Sun Fortran では、RETURN 文にある式は int の値を戻すようになっています。これは実装方式にかなり依存するため、使用しないでください。

表 11-17   選択戻り (あまり使用されません)
C が Fortran を呼び出す 例の実行
int altret_ ( int * );
main ()
{
   int k, m ;
   k =0;
   m = altret_( &k ) ;
   printf( "%d %d\n", k, m);
}
------------------------------
SUBROUTINE ALTRET( I, *, *)
  INTEGER I
  I = I + 1
  IF(I .EQ. 0) RETURN 1
  IF(I .GT. 0) RETURN 2
  RETURN
END

 demo% cc -c tst.c
 demo% f77 -o alt alt.f tst.o
 alt.f:
      altret:
 demo% alt
 1 2

 
 C ルーチンは、 Fortran ルーチンが  
RETURN 2 文を実行するため、戻り値 2 
を受け取ります。



サン・マイクロシステムズ株式会社
Copyright information. All rights reserved.
ホーム   |   目次   |   前ページへ   |   次ページへ   |   索引