共通外部データ構造には,Fortran の共通ブロックと,大域変数または外部変数として宣言された C の構造体と変数が含まれます。いずれのデータ指定も,それらを定義するルーチン外のルーチンから使用できる外部変数を作成します。
この節は,Fortran/C と Fortran/MASM の言語が混在したプログラムにのみ適用されます。Visual Basic との間で共通データを共有する方法はありません。Visual Basic と Fortran の間では,すべてのデータを引数として渡す必要があります。このプロセスは,「ユーザー定義型の処理」で説明しているユーザー定義型を渡すことで単純化することができます。
外部変数では大文字小文字が区別されるので,名付け規約の節で説明したように,言語間で大文字小文字の対応が取れている必要があります。次の節では共通外部データの交換について説明しています。
変数を Fortran と C または MASM の間で共有するには,1 つの言語で大域変数 (または COMMON) として宣言し,別の言語ではそれに外部変数として参照します。Visual Basic は,他の言語の大域データを参照したり,自分のデータを他の言語に公開することはできません。Fortran/Basic が混在したプログラムでは,変数は引数として渡す必要があります。
Fortran では,変数は ATTRIBUTES の EXTERN オプションを使って,大域変数を参照することができます。次に例を示します。
!DEC$ ATTRIBUTES C, EXTERN :: idata INTEGER idata (20)
EXTERN はコンパイラに対して,変数が別のソース・ファイルに定義され,大域変数として宣言されていることを知らせています。Fortran が変数を EXTERN で外部変数として宣言している場合,変数を公開している言語はその変数を大域変数として宣言していなくてはなりません。
C では,変数を大域変数として宣言するには次の文を使用します。
int idata[20]; // 関数の外で大域変数と宣言
MASM では,次の構文で変数を大域変数 (PUBLIC) として宣言します。
PUBLIC [langtype] name
ここで,name は引用する大域変数名で,省略可能な langtype は STDCALL または C です。省略可能な langtype は,存在する場合,.MODEL 命令で指定された呼び出し規約を置換します。
その逆に,Fortran が変数を大域変数 (COMMON) として宣言し,他の言語からこれを外部変数として参照することができます。
! PI を大域変数と宣言する Fotran コード REAL PI COMMON /PI/ PI ! 共通ブロックと変数は同じ名前を持ちます。
C で変数を外部変数として参照するには,次の文を使用します。
//PI に対する外部引用の C コード extern float PI;
C が引用する大域変数名は,Fortran 共通ブロック内の変数名ではなく,共通ブロック名であることに注意してください。このため,空白の共通ブロックを使って,C と Fortran 間でデータを参照可能にすることはできません。上の例では,共通ブロックと変数は同じ名前を持っており,2 つの言語間で変数の追跡が行いやすくなっています。明らかに,共通ブロックが複数の変数を含んでいる場合,すべての変数が共通ブロック名を持つというわけにはいきません (後述の「Fortran の共通ブロックと C の構造体の使用」を参照)。
MASM も,ATTRIBUTES EXTERN コンパイラ指示文を使って,Fortran の大域変数 (COMMON) を参照することができます。次に構文を示します。
EXTERN [langtype] name
ここで,name は引用する大域変数名で,省略可能な langtype は STDCALL または C です。
Fortran の共通ブロックと C の構造体の間で参照を行うときには,共通ブロックと構造体で,メンバ変数のメモリーへの格納方法が異なるということに注意する必要があります。Fortran は,共通ブロックの変数をできる限り詰め込んでメモリーに格納します。次にこのときの規則を示します。
共通ブロック中の 1 つの BYTE,INTEGER(1),LOGICAL(1),または CHARACTER 変数は,メモリー内の前にある変数または配列の直後から始まります。
その他のすべての型の単独変数は,メモリー内の前にある変数または配列の直後の偶数アドレスから始まります。
すべての変数配列は,メモリー内の前にある変数または配列の直後の偶数アドレスから始まりますが,CHARACTER 配列は例外で,つねに前にある変数または配列の直後から始まります。
すべての共通ブロックは 4 バイト境界のアドレスから始まります。
これら充填規則のために,C の構造体要素と Fortran の共通ブロック要素の位置合わせを考慮して,両方の言語ですべての変数を等価な型または種類にするか (両方の言語で 4 バイトと 8 バイトのデータ型だけを使うようにすれば単純になります),C のコードで C の構造体の前後に C Pack Pragmas を使って,C のデータを Fortran のデータのように詰め込むことで,要素に対応を持たせる必要があります。次に例を示します。
#pragma pack(2) struct { int N; char INFO[30]; } examp; #pragma pack()
元の状態に戻すために,構造体の終わりに #pragma pack() を追加する必要があります (注意: Fortran モジュールのデータは,適切な名付けによって,C の構造体と直接に共有することができます)。
位置合わせと充填に配慮しておけば,C から共通ブロック全体,または複数の共通ブロックを参照することができます。また,Fortran 共通ブロックの個々のメンバは,他のデータ項目と同じように引数並び中で渡すことができます。次の節では,言語が混在したデータ交換での共通ブロックの使用について説明しています。
適切な欄を持つ C の外部構造体を定義し,Fortran と C の位置合わせと充填に互換性を持たせることで,Fortran の共通ブロックを C から直接参照することができます。ATTRIBUTES オプションの C と ALIAS を使えば,共通ブロックで大文字小文字が混在した名前を使用することができます。
例として,Fortran コードに Really という名前の共通ブロックがあるとします。
!DEC$ ATTRIBUTES ALIAS:'Really' :: Really REAL(4) x, y, z(6) REAL(8) ydbl COMMON / Really / x, y, z(6), ydbl
このデータ構造をCのコードから参照するには,次の外部データ構造を使用します。
#pragma pack(2) extern struct { float x, y, z[6]; double ydbl; } Really; #pragma pack()
また,C の構造体に対応する共通ブロックを作成すれば,Fortran から C の構造体を参照することができます。これは上で説明したのと逆のケースです。しかし,共通ブロックと構造体を定義し,共通のアドレス (名前) を与え,メモリー内の位置合わせを考慮すれば,どちらの言語もこれらの変数について同じメモリー位置を使用することになるので,実装の方法はまったく同じです。
共通ブロックのアドレスを渡すには,単にブロックの第 1 変数のアドレスを渡します。つまり,第 1 変数を参照で渡すことになります。受け取り側の C または Visual C++ モジュールは,構造体を参照で受け取ります。
次の例では,C の関数 initcb は,最初の変数が n という名前の共通ブロックのアドレスを受け取りますが,これが 3 つの欄を持つ構造体へのポインタと見なします。
Fortran コード:
INTERFACE SUBROUTINE initcb (BLOCK) !DEC$ ATTRIBUTES C :: initcb !DEC$ ATTRIBUTES REFERENCE :: BLOCK INTEGER BLOCK END SUBROUTINE END INTERFACE ! INTEGER n REAL(8) x, y COMMON /CBLOCK/n, x, y ... CALL initcb( n )
C コード:
#pragma pack(2) struct block_type { int n; double x; vdouble y; }; #pragma pack() // void initcb( struct block_type *block_hed ) { block_hed->n = 1; block_hed->x = 10.0; block_hed->y = 20.0; }