言語から別の言語にデータを渡す

次の表は、XL Fortran および C 言語で使用可能なデータ型を示しています。 本節では、C プログラムへの参照によって Fortran 引き数がどのように渡されるかを説明します。 BIND(C) 属性および ISO_C_BINDING モジュール・サポートなどの Fortran 2003 ドラフト標準の相互運用可能フィーチャーを使用するには、「XL Fortran ランゲージ・リファレンス」を参照してください。

言語間での引き数の引き渡し


表 19. Fortran および C において対応するデータ型

C のルーチンは、Fortran を呼び出す時、 この表にリストされている型に対するポインターとして引き数を渡す必要があります。
XL Fortran データ型 C データ型
INTEGER(1), BYTE signed char
INTEGER(2) signed short
INTEGER(4) signed int
INTEGER(8) signed long long
REAL, REAL(4) float
REAL(8), DOUBLE PRECISION double
REAL(16) long double (注 1 を参照)
COMPLEX, COMPLEX(8) _Complex float (注 2 を参照)
COMPLEX(16), DOUBLE COMPLEX _Complex double (注 2 を参照)
COMPLEX(32) _Complex long double (注 1 および 2 を参照)
LOGICAL(1) unsigned char
LOGICAL(2) unsigned short
LOGICAL(4) unsigned int
LOGICAL(8) unsigned long long
CHARACTER char
CHARACTER(n) char[n]
Integer POINTER void *
Array array
シーケンス派生型 構造体 (C パック構造体付き)

注:

  1. 128 ビット長倍精度をサポートする C コンパイラーが必要です。 XL C は、Linux 上では -qldbl128 を正式にサポートしません。 使用には注意が必要です。
  2. C99 準拠の C コンパイラーが必要です。

注:

  1. 言語間通信では、参照または値による引き数の引き渡しで定義された %VAL および %REF 組み込み関数を 使用しなければならないことがあります。

  2. プロトタイプ化されていない C 関数を呼び出す時に、C プログラムは浮動小数点値を倍精度へ、および短精度整数値へと 自動的に変換します。 XL Fortran は、値によって引き渡された REAL(4) の数量に対して変換を実行しないので、関数プロトタイプで 宣言していない C 関数の引き数として REAL(4) 値と INTEGER(2) 値を渡さないでください。

  3. Fortran 派生型および C の構造体が、互換データ型であるためには、 サブオブジェクトの数、データ型、および長さが一致している必要があります。
関連情報:
ディレクトリー /opt/ibmcmp/xlf/9.1/samples の 1 つ または複数のサンプル・プログラムは、Fortran から C への呼び出し方法を説明しています。

XL Fortran によって提供される Fortran 2003 ドラフト標準の相互運用可能フィーチャーを使用するには、 「XL Fortran ランゲージ・リファレンス」の 『言語相互運用可能フィーチャー』を参照してください。

言語間でのグローバル変数の引き渡し

Fortran プログラム内から C データ構造体にアクセスする場合、あるいは C プログラム内から共通ブロックにアクセスする場合は、 次のようにします。

  1. C 構造体メンバーの 1 対 1 マッピングを提供する名前付き共通ブロックを作成します。 名前なし共通ブロックがある場合は、名前付き共通ブロックに変更します。 その共通ブロックには、C 構造体の名前を付けます。
  2. C 構造体をグローバル変数として宣言します。 宣言は、関数の外に置くか、extern 修飾子を持つ関数内に置きます。
  3. C ソース・ファイルをコンパイルしてパック構造体を取得します。

 program cstruct                         struct mystuff {
 real(8) a,d                                    double a;
 integer b,c                                    int b,c;
 .                                              double d;
 .                                       };
 common /mystuff/ a,b,c,d
 .                                       main() {
 .
 end                                     }

名前付き共通ブロックを特に必要としない場合は、C 構造体と同じ 1 対 1 マッピングを指定してシーケンス派生型を 作成し、C 関数に引き数として渡すことができます。 C ソース・ファイルをコンパイルしてパック構造体を取得する必要があります。

THREADLOCAL と宣言された共通ブロックは、コンパイラー生成コードにより動的に割り振られる、 スレッド固有のデータ域です。 静的ブロックは THREADLOCAL 共通ブロック用に予約済みのままですが、コンパイラーおよび コンパイラーの実行時環境が制御情報用にそれを使用します。 THREADLOCAL 共通ブロックを Fortran と C プロシージャーとの間で共用する必要がある場合、 C ソースには THREADLOCAL 共通ブロックのインプリメンテーションを知らせておく必要があります。 詳細については、「XL Fortran ランゲージ・リファレンス」の 『ディレクティブ』の節にある 『THREADLOCAL』共通ブロック、および 付録 A, サンプルの Fortran プログラムを参照してください。

THREADPRIVATE と宣言されている共通ブロックへの アクセスは、THREADPRIVATE として 宣言されている C グローバル変数を使用して行うことができます。

言語間での文字型の引き渡し

言語間呼び出しの難しい面の 1 つは、言語間で文字ストリングを引き渡すことです。 これが困難なのは、以下に示すように、 複数の異なる言語がそのようなエンティティーを表す方法が異なるためです。

混合言語プログラムとして両方の部分を作成している場合、C ルーチンに 追加の Fortran 長さ引き数を処理させるようにすることもできますし、 %REF 関数を使用してストリングを渡すことによってこの追加引き数を 抑止することもできます。 %REF (通常はあらかじめ存在している C ルーチン用) を使用すると、 C ルーチンに渡される個々のストリングの終わりにヌルを連結して、 どこでストリングが終わるかを示す必要があります。

! Initialize a character string to pass to C.
               character*6 message1 /'Hello¥0'/
! Initialize a character string as usual, and append the null later.
               character*5 message2 /'world'/
 
! Pass both strings to a C function that takes 2 (char *) arguments.
               call cfunc(%ref(message1), %ref(message2 // '¥0'))
               end

C 言語の使用との互換性を得るために、XL Fortran ストリングで以下のエスケープ・シーケンスをエンコードすることが できます。

表 20. 文字ストリングのエスケープ・シーケンス

エスケープ 意味
¥b バックスペース
¥f 用紙送り
¥n 改行
¥r 改行
¥t タブ
¥0 ヌル
' アポストロフィ (ストリングは終了しません)
" 二重引用符 (ストリングは終了しません)
  円記号
¥x x。ここで x は任意の文字 (円記号は無視されます)

ストリング内で円記号をエスケープ・シーケンスとして解釈させたくない場合は、 -qnoescape オプションを指定してコンパイルすることができます。

言語間での配列の引き渡し

Fortran は、配列エレメントを昇順で記憶単位に保管します。 C は、 行順に配列エレメントを保管します。 Fortran 配列指標は 1 から開始しますが、C 配列指標は 0 から開始します。

以下の例は、Fortran および C で A(3,2) によって 宣言された 2 次元の配列がどのように保管されるかを示しています。

表 21. Fortran および C の対応する配列レイアウト

Fortran の配列参照 A(X,Y,Z) は、C では a[Z-1][Y-1][X-1] で表現します。 C では個々のスカラー配列エレメントは値によって渡しますが、 配列は参照によって渡すことに注意してください。
  Fortran エレメント名 C エレメント名
一番低い記憶単位 A(1,1) A[0][0]
  A(2,1) A[0][1]
  A(3,1) A[1][0]
  A(1,2) A[1][1]
  A(2,2) A[2][0]
一番高い記憶単位 A(3,2) A[2][1]

Fortran 配列のすべてまたは一部を他の言語に渡すには、 Fortran 90 または Fortran 95 配列表記を使用することができます。

REAL, DIMENSION(4,8) :: A, B(10)
 
! Pass an entire 4 x 8 array.
CALL CFUNC( A )
! Pass only the upper-left quadrant of the array.
CALL CFUNC( A(1:2,1:4) )
! Pass an array consisting of every third element of A.
CALL CFUNC( A(1:4:3,1:8) )
! Pass a 1-dimensional array consisting of elements 1, 2, and 4 of B.
CALL CFUNC( B( (/1,2,4/) ) )

必要な場合は、Fortran プログラムは一時配列を作成して、すべてのエレメントを連続するストレージにコピーします。 あらゆる場合に、C ルーチンは配列の列順レイアウトを考慮に入れる必要があります。

配列セクションまたは不連続配列は、対応する仮引き数が想定形状配列またはポインターとして宣言される場所に 明示インターフェースが存在しないと、連続する一時アドレスとして渡されます。 配列引き数で Fortran 以外のプロシージャーを呼び出す時に、配列記述子 (言語間呼び出しに対してサポートされて いない) の作成を回避するために、Fortran 以外のプロシージャーに明示インターフェースを与えたり、 対応する仮引き数をインターフェースの想定形状配列またはポインターとして宣言しないでください。

! This explicit interface must be changed before the C function
! can be called.
INTERFACE
  FUNCTION CFUNC (ARRAY, PTR1, PTR2)
    INTEGER, DIMENSION (:) :: ARRAY          ! Change this : to *.
    INTEGER, POINTER, DIMENSION (:) :: PTR1  ! Change this : to *
                                             ! and remove the POINTER
                                             ! attribute.
    REAL, POINTER :: PTR2                    ! Remove this POINTER
                                             ! attribute or change to TARGET.
  END FUNCTION
END INTERFACE

言語間のポインターの引き渡し

整数 POINTER は、常に pointee オブジェクトのアドレスを表し、 次のように、必ず値によって渡す必要があります。

CALL CFUNC(%VAL(INTPTR))

Fortran 90 POINTER は、言語間でやりとりすることはできますが、これは呼び出されたプロシージャーに対して 明示インターフェースが存在しない場合にのみ、あるいは、明示インターフェース内の引き数が POINTER 属性 または想定形状宣言子を持っていない場合に限られます。 POINTER 属性を除去したり、TARGET に変更したり、さらに形状無指定配列の配列宣言子があれば、 形状明示型または大きさ引き継ぎに変更することができます。

XL Fortran では参照によって呼び出すという規則があるので、他言語からのスカラー値であっても、値そのものではなく 値のアドレスとして渡す必要があります。 たとえば、整数値 x を Fortran へ渡す C 関数は &x を渡す必要があります。 さらに、ポインター値 p を整数 POINTER として使用できるように Fortran に渡す C 関数は その値を void **p として宣言する必要があります。 C の配列は例外で、& 演算子なしで Fortran に渡すことができます。

参照または値による引き数の引き渡し

Fortran 以外の言語で書かれたサブプログラム (たとえば、ユーザー作成 C プログラム、 オペレーティング・システム・ルーチンなど) を呼び出すためには、Fortran が使用するデフォルトの方式とは 異なる方式で実引き数を渡さなければならない場合があります。 C ルーチン (libc.so などのようなシステム・ライブラリー内の C ルーチンも含む) は、引き数を参照によって渡すのではなく、 値によって渡す必要があります。 (C は、個々のスカラー配列エレメントを値によって渡しますが、配列は参照によって渡します。)

デフォルトの引き渡し方法は、CALL ステートメントまたは関数参照の引き数リスト内で 組み込み関数 %VAL および %REF を使用して変更することができます。 これらの組み込み関数を、Fortran プロシージャー参照の引き数リストまたは選択戻り指定子で使用することは できません。

%REF
参照によって引き数を渡します (つまり、呼び出されたサブプログラムは引き数のアドレスを受け取ります)。 これは、文字ストリングに対して余分な長さ引き数の抑止も行うということを除き、Fortran のデフォルト呼び出し方式と 同じです。

%VAL
値によって引き数を渡します (つまり、呼び出されたサブプログラムは、実引き数と同じ値を持つ引き数を 受け取りますが、この引き数に対して加えられた変更は、実引き数には影響しません)。

この組み込み関数は、型が CHARACTER(1) 式、BYTE 式、論理式、整数式、実数式、 複素数式、またはシーケンス派生型のいずれかである実引き数で使用することができます。 派生型のオブジェクトに、ポインター、配列、または長さが 1 バイトよりも長い文字構造体コンポーネントを 入れることはできません。

%VAL は、長さが 1 バイトよりも長い配列エンティティー、プロシージャー名、文字式である 実引き数で使用することはできません。

%VAL を使用すると、XL Fortran は実引き数を 32 ビット または 64 ビットの中間値として渡します。

32 ビット・モード

実引き数が、次のいずれかである場合:

  • 32 ビットより短い整数値または論理値の場合は、符号付きの 32 ビット値に拡張されます。
  • 32 ビットよりも長い整数値または論理値の場合は、2 つの 32 ビット中間値として渡されます。
  • 実数式または複素数式の場合は、複数の 64 ビット中間値として渡されます。
  • シーケンス派生型の場合は、複数の 32 ビット中間値として渡されます。

バイト名付き定数および変数は、INTEGER(1) であるかのように渡されます。 実引き数が CHARACTER(1) の場合は、-qctyplss コンパイラー・オプションを指定したか どうかに関係なく、32 ビット値になるまでコンパイラーが左側にゼロを埋め込みます。

64 ビット・モード

実引き数が、次のいずれかである場合:

  • 64 ビットより短い整数値または論理値の場合は、符号付きの 64 ビット値に拡張されます。
  • 実数式または複素数式の場合は、複数の 64 ビット中間値として渡されます。
  • シーケンス派生型の場合は、複数の 64 ビット中間値として渡されます。

バイト名付き定数および変数は、INTEGER(1) であるかのように渡されます。 実引き数が CHARACTER(1) の場合は、-qctyplss コンパイラー・オプションを指定したか どうかに関係なく、64 ビット値になるまでコンパイラーが左側にゼロを埋め込みます。

-qautodbl コンパイラー・オプションを指定した場合、埋め込まれたストレージ・スペースは、派生型のオブジェクト以外には渡されません。

  EXTERNAL FUNC
  COMPLEX XVAR
  IVARB=6
 
  CALL RIGHT2(%REF(FUNC))       ! procedure name passed by reference
  CALL RIGHT3(%VAL(XVAR))       ! complex argument passed by value
  CALL TPROG(%VAL(IVARB))       ! integer argument passed by value
  END

%VAL および %REF 用の明示インターフェース

Fortran 以外のプロシージャーに対して明示インターフェースを 以下のよう指定して、個々の引き数リスト内の %VAL および %REF への 呼び出しのコーディングを回避することができます。

INTERFACE
    FUNCTION C_FUNC(%VAL(A),%VAL(B)) ! Now you can code "c_func(a,b)"
        INTEGER A,B                  ! instead of
    END FUNCTION C_FUNC              ! "c_func(%val(a),%val(b))".
END INTERFACE

gcc への複合値の引き渡し

Fortran と Gnu C++ との間での複合値の引き渡しは、-qfloat=[no]complexgcc サブオプションに 何が指定されているかによって異なります。 -qfloat=complexgcc が指定されている場合、複素数を渡すか、または戻すときにコンパイラーは Linux 規則を使用します。 -qfloat=nocomplexgcc がデフォルトです。

32 ビット・モードの -qfloat=complexgcc では、コンパイラーは COMPLEX *8 値を 2 つの汎用レジスター (GPR) に入れて渡し、COMPLEX *16 値を 4 つの GPR に入れて渡します。 64 ビット・モードでは、COMPLEX *8 値は 1 つの GPR に入れて 渡され、COMPLEX *16 値は 2 つの GPR に入れて渡されます。-qfloat=nocomplexgcc の場合、COMPLEX *8 値と COMPLEX *16 値が 2 つの 浮動小数点レジスター (FPR) に入れて渡されます。 -qfloat=complexgcc-qfloat=nocomplexgcc では、COMPLEX *32 値は常に 4 つの FPR に入れて渡されます (gccCOMPLEX*32 をサポートしないため)。

32 ビット・モードの -qfloat=complexgcc では、COMPLEX *8 値は GPR3 から GPR4 に戻され、COMPLEX *16 は GPR3 から GPR6 に戻されます。 64 ビット・モードでは、COMPLEX *8 値は GPR3 に戻され、COMPLEX *16 値は GPR3 から GPR4 に戻されます。 -qfloat=nocomplexgcc の場合、COMPLEX *8 値と COMPLEX *16 値が FPR1-FPR2 に戻されます。 -qfloat=complexgcc-qfloat=nocomplexgcc では、COMPLEX *32 は常に FPR1-FPR4 に 戻されます。

Fortran 関数からの値の戻り

XL Fortran は、Fortran 以外のプロシージャーからのある種の呼び出しを サポートしていません。 Fortran 関数がポインター、配列、または不定長の文字を戻す場合は、 Fortran 以外からその関数を呼び出さないでください。

以下のような関数を間接的に呼び出すことはできます。

SUBROUTINE MAT2(A,B,C)    ! You can call this subroutine from C, and the
                          ! result is stored in C.
INTEGER, DIMENSION(10,10) :: A,B,C
C = ARRAY_FUNC(A,B)       ! But you could not call ARRAY_FUNC directly.
END

OPTIONAL 属性を持つ引き数

オプションの引き数を参照によって引き渡す場合、引き数が存在しなければ、引き数リスト内のアドレスはゼロです。

オプションの引き数を値によって引き渡す場合、引き数が存在しなければ値はゼロです。 コンパイラーは追加のレジスター引き数を使用して、その値を通常のゼロ値と区別します。 レジスターが値 1 を持っている場合は、オプションの引き数が存在します。 値 0 を持っている場合は、オプションの引き数は存在しません。

関連情報:
引き数リスト内の引き数の順序を参照してください。

INTENT 属性を持つ引き数

現在では、INTENT 属性を持つ引き数を宣言しても、 プロシージャーに対するリンケージ規約は変更されません。 しかし、この規則は将来変更される可能性があるので、Fortran 以外の プロシージャーから INTENT(IN) 引き数を 持つ Fortran プロシージャーへの呼び出しはお勧めできません。

型のエンコードと検査

実行時エラーは見つけにくく、多くの場合、 プロシージャー・インターフェースの不一致またはデータ定義の 矛盾が原因です。 そのため、これらの問題のできるだけ多くをコンパイル時またはリンク時に 見つけることが得策です。 IBM Copyright 2003