Fortran 95/90 では、配列を配列要素、配列サブセクション、または配列名で参照される配列全体として渡すことができます。Fortran では、配列要素は列優先順に編成されていて、最初の添字 (次元) から優先されます。
Fortran と他の言語の間で配列を使用する場合、要素のインデックスと順序を考慮する必要があります。配列要素は個別に参照し、追跡する必要があります。配列のインデックス付けは、ソースレベルでの問題であり、下位のデータに違いはありません。
Fortran および C の配列は、次の 2 つの点で異なります。
配列の下限の値が異なります。Fortran のデフォルトでは、配列の先頭の要素のインデックスは 1 です。C および C++ では、0 です。したがって、Fortran の添字は 1 つ大きい値に設定しなければなりません (Fortran には、別の整数で下限を指定するオプションもあります)。
多重次元配列の場合、Fortran は最も左のインデックスから優先するのに対し、C では最も右のインデックスから優先します。これは、それぞれ列優先順および行優先順と呼ばれることがあります。
C では、X[3][3] として宣言されている配列の最初の 4 つの要素は次のとおりです。
X[0][0] X[0][1] X[0][2] X[1][0]
一方、Fortran では、最初の 4 つの要素は次のとおりです。
X(1,1) X(2,1) X(3,1) X(1,2)
インデックスの順序は、次元をいくつ宣言しても同じです。例えば、次のような C の宣言を考えてみます。
int arr1[2][10][15][20];
これは Fortran の次の宣言に相当します。
INTEGER arr1( 20, 15, 10, 2 )
C の配列宣言に使用される定数は、他の言語のように上限ではなく、範囲を表しています。このため、int arr[5][5] と宣言された C 配列の最後の要素は、arr[5][5] ではなく arr[4][4] となります。
次の表に、対応する配列宣言を示します。
言語 |
配列宣言 |
Fortran からの配列参照 |
---|---|---|
Fortran |
DIMENSION x(i, k) または type x(i, k) |
x(i, k) |
C/C++ |
type x[ k ] [ i ] |
x( i -1, k -1) |
Visual Basic および MASM の情報は、Windows* システムのみが対象になります。
Visual Basic から Fortran に配列を渡すには、配列の最初の要素を渡します。デフォルトでは、Visual Basic は変数を参照によって渡すため、配列の最初の要素を渡すと、Fortran には Fortran が期待しているとおりに、配列の開始位置が与えられます。Visual Basic のデフォルトでは最初の配列要素のインデックスは 0 ですが、Fortran のデフォルトは 1 です。次の文を使用すると、Visual Basic のインデックス付けを 1 から開始させることができます。
Option Base 1
別の方法として、いずれの言語でも、配列宣言中で、配列の下限を -32,768 ~ 32,767 の範囲の任意の整数に設定することができます。次に例を示します。
' In Basic Declare Sub FORTARRAY Lib "fortarr.dll" (Barray as Single) DIM barray (1 to 3, 1 to 7) As Single Call FORTARRAY(barray (1,1)) ! In Fortran Subroutine FORTARRAY(arr) REAL arr(1:3,1:7)
MASM では、配列は 1 次元であり、配列要素はバイト単位に参照しなければなりません。アセンブラーにより、配列の要素はメモリー内に連続して格納され、最初のアドレスが配列名によって参照されます。個々の要素を参照するには、最初の要素を基準として、目的の要素の前にある要素の合計バイト数を読み飛ばします。次に例を示します。
xarray REAL4 1.1, 2.2, 3.3, 4.4 ; initializes ; a four element array with ; each element 4 bytes
MASM での xarray の参照は最初の要素、すなわち 1.1 を含む要素を参照します。第 2 の要素を参照するには、最初の要素の 4 バイト後にある要素を、xarray[4] または xarray+4 で参照する必要があります。次に別の例を示します。
yarray BYTE 256 DUP ; establishes a ; 256 byte buffer, no initialization zarray SWORD 100 DUP(0) ; establishes 100 ; two-byte elements, initialized to 0
Fortran 95/90 が複数のポインター・メモリー・アドレスを追跡しなければならない場合に備えて、インテル® Fortran コンパイラーは、配列の編成に関する詳細情報を格納する配列記述子 を使用します。
(結合またはプロシージャー・インターフェイス・ブロックによる) 明示的なインターフェイスを使用する場合、インテル® Fortran は次の形式の配列引数記述子を生成します。
一部のデータ構造体引数は、適切な明示的インターフェイスが提供されている場合でも、記述子を使用しません。例えば、明示的形状配列および形状引き継ぎ配列は記述子を使用しません。一方、配列ポインターおよび割付け配列は、引数として使用するかどうかにかかわらず、記述子を使用します。
インテル® Fortran と Fortran 以外の言語 (C など) の間で呼び出しを行う場合、暗黙的 インターフェイスを使用することで、インテル® Fortran の記述子なしで配列を渡すことができます。ただし、呼び出されたルーチンがインテル® Fortran 記述子に含まれる情報を必要とする場合、ルーチンを明示的 インターフェイスで宣言し、仮配列を形状引き継ぎ配列またはポインター属性として指定します。
Fortran 95/90 ポインターは、(配列境界が "矩形" である限り) 任意の形式で編成された任意のメモリー部分と関連付けることができます。また、Fortran 95/90 ポインターを C などの他の言語に渡し、その言語で記述子を正しく解釈して、必要な情報を取得することができます。
ただし、配列記述子を使用すると、エラーが起こる可能性が高くなります。また、対応するコードの移植性も損なわれます。特に、次のことに注意してください。
記述子が正しく定義されていない場合、プログラムは間違ったメモリーアドレスを参照し、一般保護違反を発生させることがあります。
配列記述子の書式は、各 Fortran コンパイラーに対して固有です。配列記述子を使用するコードは、他のコンパイラーやプラットフォームへ移植できません。例えば、現在のインテル® Fortran の配列記述の書式は、インテル® Fortran 7.0 の配列記述の書式と異なります。
配列記述子の書式は、将来変更される可能性があります。
コンパイラーによりビルドされた記述子は、ユーザーが変更することはできません。既存の記述子のフィールドを変更することは不正です。
次に、IA-32 アーキテクチャーのシステム上における現在のインテル® Fortran の配列記述子のコンポーネントを示します。
最初のロングワード (バイト 0 から 3) には、ベースアドレスが含まれています。ベースアドレスとオフセットは、配列の最初のメモリー位置 (開始) を定義します。
2 番目のロングワード (バイト 4 から 7) には、配列の 1 つの要素のサイズが含まれています。
3 番目のロングワード (バイト 8 から 11) には、A0 オフセットが含まれています。A0 オフセットをベースアドレスに加えて、インデックスがすべて 0 の要素のアドレス (実配列の境界外であっても) を求めます。これは、配列要素のアドレスを計算するのに役立ちます。
4 番目のロングワード (バイト 12 から 15) には、配列の情報を保存するのに使用されるフラグのセットが含まれます。含まれるセットは次のとおりです。
5 番目のロングワード (バイト 16 から 19) には、配列の次元 (次元数) が含まれています。
6 番目のロングワード (バイト 20 から 23) は、予約済みです。明示的に指定してはなりません。
残りのロングワード (バイト 24 から 107) には、個々の (最大 7 つまでの) 次元に関する情報が含まれています。各次元は、さらに 3 つのロングワードによって記述されます。
次元数 1 の配列は、3 つのロングワードを追加する必要があるため、合計で 9 つのロングワード (6 + 3*1) が含まれ、バイト 35 で終わります。次元数 7 の配列は、合計で 27 のロングワード (6 + 3*7) が含まれ、バイト 107 で終わります。
例えば、次のような宣言の場合を考えてみます。
integer,target :: a(10,10) integer,pointer :: p(:,:) p => a(9:1:-2,1:9:3) call f(p) . . .
実引数 p の記述子には、次の値が含まれます。
最初のロングワード (バイト 0 から 3) には、ベースアドレスが含まれます (ランタイムで割り当てられます)。
2 番目のロングワード (バイト 4 から 7) は、4 (1 つの要素のサイズ) に設定されます。
3 番目のロングワード (バイト 8 から 11) には、A0 オフセット (-112) が含まれています。
4 番目のロングワード (バイト 12 から 15) には、3 が含まれます (配列は定義済み、割り当て解除は不可)。
5 番目のロングワード (バイト 16 から 19) には、2 が含まれます (次元数)。
6 番目のロングワード (バイト 20 から 23) は、予約済みです。
7、8、および 9 番目のロングワード (バイト 24 から 35) には、最初の次元に関する次の情報が含まれています。
10、11、および 12 番目のロングワード (バイト 36 から 47) には、2 番目の次元に関する次の情報が含まれています。
この例では、バイト 47 が最後のバイトとなります。
インテル® 64 および IA-64 アーキテクチャー・ベースのシステムの記述子は、IA-32 アーキテクチャー・ベースのシステムの記述子と同じ書式を使用しますが、すべてのフィールドが 4 バイトから 8 バイトになります。
インテル® 64 アーキテクチャー・ベースの Linux* システムで、2GB を超える配列を使用するプログラムをコンパイルする場合、-mcmodel=medium または -mcmodel=large コンパイラー・オプションと -shared-intel オプションを指定する必要があります。詳細は、「インテル® 64 アーキテクチャー・ベースのシステムで使用するメモリーモデルの指定」を参照してください。