次の表は、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 パック構造体付き) |
注:
|
注:
XL Fortran によって提供される Fortran 2003 ドラフト標準の相互運用可能フィーチャーを使用するには、 「XL Fortran ランゲージ・リファレンス」の 『言語相互運用可能フィーチャー』を参照してください。
Fortran プログラム内から C データ構造体にアクセスする場合、あるいは 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 ストリングで以下のエスケープ・シーケンスをエンコードすることが
できます。
エスケープ | 意味 |
---|---|
¥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 プロシージャー参照の引き数リストまたは選択戻り指定子で使用することは できません。
この組み込み関数は、型が CHARACTER(1) 式、BYTE 式、論理式、整数式、実数式、 複素数式、またはシーケンス派生型のいずれかである実引き数で使用することができます。 派生型のオブジェクトに、ポインター、配列、または長さが 1 バイトよりも長い文字構造体コンポーネントを 入れることはできません。
%VAL は、長さが 1 バイトよりも長い配列エンティティー、プロシージャー名、文字式である 実引き数で使用することはできません。
%VAL を使用すると、XL Fortran は実引き数を 32 ビット または 64 ビットの中間値として渡します。
32 ビット・モード |
---|
実引き数が、次のいずれかである場合:
バイト名付き定数および変数は、INTEGER(1) であるかのように渡されます。 実引き数が CHARACTER(1) の場合は、-qctyplss コンパイラー・オプションを指定したか どうかに関係なく、32 ビット値になるまでコンパイラーが左側にゼロを埋め込みます。 |
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
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
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 に入れて渡されます (gcc が COMPLEX*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 に 戻されます。
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
オプションの引き数を参照によって引き渡す場合、引き数が存在しなければ、引き数リスト内のアドレスはゼロです。
オプションの引き数を値によって引き渡す場合、引き数が存在しなければ値はゼロです。 コンパイラーは追加のレジスター引き数を使用して、その値を通常のゼロ値と区別します。 レジスターが値 1 を持っている場合は、オプションの引き数が存在します。 値 0 を持っている場合は、オプションの引き数は存在しません。
現在では、INTENT 属性を持つ引き数を宣言しても、 プロシージャーに対するリンケージ規約は変更されません。 しかし、この規則は将来変更される可能性があるので、Fortran 以外の プロシージャーから INTENT(IN) 引き数を 持つ Fortran プロシージャーへの呼び出しはお勧めできません。
実行時エラーは見つけにくく、多くの場合、
プロシージャー・インターフェースの不一致またはデータ定義の
矛盾が原因です。 そのため、これらの問題のできるだけ多くをコンパイル時またはリンク時に
見つけることが得策です。