言語が混在したプログラミングにおける共通外部データの使用

共通外部データ構造には、Fortran の共通ブロック、およびグローバル変数または外部変数として宣言された C の構造体と変数が含まれます。いずれのデータ指定も、それらを定義するルーチン外のルーチンから使用できる外部変数を作成します。

外部変数では大文字と小文字を区別するため、命名規則のセクションで説明されているように、異なる言語の間で大文字と小文字が一致している必要があります。次のセクションでは、共通外部データの交換について説明します。

言語が混在したプログラミングにおけるグローバル変数の使用

Fortran と C で変数を共有するには、1 つの言語で変数をグローバル変数 (または COMMON) として宣言し、別の言語でその変数を外部変数としてアクセスします。Fortran プログラムの場合、変数は引数として渡す必要があります。

Fortran の変数は、ATTRIBUTES の EXTERN オプションを使用して、グローバル・パラメータにアクセスすることができます。次に例を示します。

    !DEC$ ATTRIBUTES C, EXTERN :: idata    INTEGER idata (20)


EXTERN オプションは、変数が別のソースファイルで定義され、グローバル変数として宣言されていることをコンパイラに伝えます。Fortran が EXTERN オプションを使用して変数を外部変数として宣言する場合、変数を共有している言語はその変数をグローバル変数として宣言する必要があります。

C の場合、変数は次の文を使用してグローバル変数として宣言されます。

  int idata[20]; // declared as global (outside of any function)


Fortran は、変数をグローバル変数 (COMMON) として宣言し、他の言語ではその変数を外部変数として参照することができます。

 ! Fortran declaring PI global  REAL PI  COMMON /PI/ PI ! Common Block and variable have the same name


C の場合、変数は次の文を使用して外部変数として参照されます。

  //C code with external reference to PI0  extern float PI;


C が参照するグローバル変数名は、Fortran の共通ブロック内の変数名ではなく、共通ブロック名であることに注意してください。したがって、空白の共通ブロックを使用して、C と Fortran の間でデータを参照することはできません。上の例では、共通ブロック名と変数名が同じため、2 つの言語の間における変数を把握するのに役立ちます。共通ブロックが複数の変数を含む場合、すべての変数に同じ共通ブロック名を使用することはできません。(「Fortran の共通ブロックおよび C の構造体の使用」を参照してください。)

Fortran の共通ブロックおよび C の構造体の使用

Fortran の共通ブロックおよび C の構造体の間で参照を行う場合、メンバ変数をメモリに格納する方法が共通ブロックと構造体で異なるということに注意する必要があります。Fortran は次の規則に従って、共通ブロックの変数を最大限にパックしてメモリに格納します。

これらのパディング規則があるため、C の構造体要素と Fortran の共通ブロック要素のアライメントを考慮して、両方の言語ですべての変数を同じ型または種類にするか (両方の言語で 4 バイトおよび 8 バイトのデータ型のみ使用することで、簡単にこの作業を行うことができます)、または C のコードで C の構造体の前後に C のパックプラグマを使用して、C のデータを Fortran のデータのようにパックすることで、要素の一致を保証する必要があります。次に例を示します。

 #pragma pack(2) struct {         int N;         char INFO[30]; } examp; #pragma pack()


元のパック状態に戻すには、構造体の終わりに #pragma pack( ) を追加する必要があります。(注意: Fortran モジュールのデータは、適切な名前を使用することで、C の構造体と直接に共有することができます。)

アライメントおよびパディングを考慮しておけば、C 言語から共通ブロック全体、または複数の共通ブロックにアクセスすることができます。また、Fortran 共通ブロックの個々のメンバは、その他のデータ項目と同じように引数リストで渡すことができます。次のセクションでは、言語が混在したデータ交換における共通ブロックの使用について説明します。

共通ブロックおよび C の構造体への直接アクセス

適切なフィールドが含まれた 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 の構造体にアクセスすることもできます。これは上記に説明したものと逆のケースです。ただし、共通ブロックと構造体の定義、共通のアドレス (名前) の提供、およびメモリ内のアライメントが行われている場合、どちらの言語も変数の同じメモリ位置を共有するため、実装の方法は同じです。

共通ブロックのアドレスの受け渡し

共通ブロックのアドレスを渡すには、ブロックにある最初の変数のアドレスを渡します。つまり、最初の変数を参照によって渡します。受け取り側の C または 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;   double y; }; #pragma pack() // void initcb( struct block_type *block_hed )  {    block_hed->n = 1;    block_hed->x = 10.0;    block_hed->y = 20.0; }