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

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

このセクションの説明は、Fortran と C が混在したプログラム、および (Windows* の場合) Fortran と MASM が混在したプログラムにのみ当てはまります。

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

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

Fortran と C または Fortran と MASM で変数を共有するには、1 つの言語で変数をグローバル変数 (または COMMON) として宣言し、別の言語でその変数に外部変数としてアクセスします。

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)

MASM では、次の構文でグローバル・パラメーター (PUBLIC) を宣言します。

PUBLIC [langtype] name

ここで、name は参照するグローバルデータ名で、省略可能な langtype は STDCALL または C になります。langtype オプションを指定すると、.MODEL 宣言子で指定された呼び出し規則が無効になります。

逆に、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 PI
  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 の共通ブロックおよび 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;
 }