基底付き変数

BASED 属性は、ロケーターを使用してアクセスする記憶域のテンプレートを定義します。基底付き変数は記憶域の記述ではありますが、他の属性と異なり、固有の記憶域がありません。記憶域がないためアドレスもありません。次に例を示します。

DECLARE X CHARACTER(30) BASED; 
DECLARE P POINTER;
   .
   .
   .
P->X = 'ABC';

この例で、P にアドレスまたはポインターの値が代入されているとします。参照 P–>X はポインターで修飾された参照です。この参照を使用して、P でアドレス指定された記憶域への代入を行い、記憶域に X のような文字列変数が格納されているものとして扱うことができます。

ポインターの値は、主に 2 つの方法で取得することができます。ADDR 組み込み関数で計算されて返される変数の記憶域のアドレスから取得する方法と、ALLOCATE 文で動的に取得される記憶域のアドレスから取得する方法です。次に例を示します。

DECLARE K FIXED BINARY(15); 
DECLARE X(5) FLOAT BINARY; 
DECLARE Y FLOAT BINARY BASED; 
DECLARE P POINTER;
   .
   .
   .
P = ADDR(X(K));
P->Y = 10;

この例では、ADDR 組み込み関数から返される X (K) のアドレスが P に代入されます。2 つ目の代入でテンプレート Y に従って P が示す記憶域の場所に値 10 が格納されているため、X (K) には実質的に 10 が代入されます。

ポインターの値を取得する 3 つ目の方法として、POINTER 組み込み関数を使用する方法もあります。この方法では、領域のオフセットの値をポインターに変換することができます。

ポインターを使いすぎるとプログラムが読みにくくなり、代入によって予期しない副作用が発生する可能性もあるため、他の変数の記憶域へのアクセスにもポインターを無計画に使用することはお勧めしません。また、基底付き変数のデータ記述については、参照記憶域の宣言との互換性のチェックが行われないことに注意してください。たとえば、Y の宣言で X の要素のデータ型と互換性がないデータ型が宣言されていると、文 P–>Y = 10 で想定した結果が得られないことがあります。基底付き変数を使用した記憶域の共有の詳細については、「記憶域の共有」のセクションを参照してください。

ALLOCATE 文で基底付き変数を使用して記憶域ブロックを割り当てると、それらの記憶域ブロックに基底付き変数と ALLOCATE 文から返されるロケーターを使用してアクセスできるようになります。次に例を示します。

DECLARE P POINTER;
DECLARE X(C,N) CHAR BASED(P);
N = 10; 
C = 10;
ALLOCATE X SET(P);
   .
   .
   .
P -> X(10,5) = 'A';

上記の例では、ALLOCATE 文で、100 個の 1 バイト文字の値で構成される 2 次元配列を保持する十分なサイズの記憶域ブロックを割り当て、その記憶域ブロックへのポインターを P に代入しています。その後の P–>X は、その記憶域ブロックへの参照であり、100 個の 1 バイト文字の値の配列を参照します。

基底付き変数には、他の変数と同様に添え字を付けることができます。たとえば、上記の例の P–> X (10,5) = 'A' という文は、P で修飾された配列の 10 行目の列 5 の要素に文字「A」を代入します。ポインター変数も配列にできるため、ポインター変数にも添え字を付けることができます。次に例を示します。

DECLARE P(3) POINTER; 
DECLARE X(10) FLOAT BASED;
   .
   .
   .
ALLOCATE X SET(P(K));

上記の例で、P (K)–>X は、P の K 番目のポインター要素で修飾された 10 個の浮動小数点要素の配列全体を参照します。同様に、P (K) –>X (J) は、ポインター配列 P の K 番目の要素で修飾された浮動小数点配列の J 番目の要素を参照します。

基底付き変数を明示的または暗黙的なロケーター修飾子なしで使用できるのは ALLOCATE 文だけです。この場合、基底付き変数は、割り当てる記憶域の量を記述する目的で使用されます。

暗黙のロケーター修飾は、基底付き変数への複数の参照で同じポインターを使用する場合に使用できる簡略表記です。次に例を示します。

DECLARE X(10) FLOAT BASED(P); 
DECLARE P POINTER;
   .
   .
   .
ALLOCATE X SET(P);

上記の例では、X が P を基底として宣言されているため、X (K)、X (5)、X のような修飾なしの X への参照は暗黙的に P で修飾され、P–>X (K)、P–>X (5)、P–>X と同じになります。暗黙的な修飾は、Q–>X のような明示的な修飾で一時的にオーバーライドできます。明示的な修飾は、BASED (P) の P の指定による影響を受けません。

基底付き変数の範囲は、整数値の式として指定できます。範囲は変数を割り当てるか参照するたびに評価されます。ALLOCATE 文で記憶域を割り当てるときは、範囲はキャプチャされません。範囲の式では、それらの変数の値が基底付き変数を参照する前の値であれば、同じブロックで宣言された変数を参照することができます。範囲の式で参照される変数の値を変更すると、基底付き変数の範囲が変わります。次に例を示します。

DECLARE X(N) CHARACTER(1) BASED;

N = 10;
ALLOCATE X SET(P);
   .
   .
   .
N = M;
P->X(5) = 'A';

この例では、ALLOCATE 文で 10 個の要素の配列を割り当てています。M の値は 5 以上 10 以下でなければなりません。それ以外の場合、P–>X (5) への参照が無効になり、予期しない結果になることがあります。

ALLOCATE 文で割り当てた記憶域ブロックを解放するには、FREE 文を使用します。次に例を示します。

FREE P->X;

解放した記憶域にはアクセスできなくなり、そのブロックを指す P などのポインターを使用すると予期しない結果になります。

注:

ALLOCATE 文で取得された記憶域は、明示的な FREE でしか解放されません。プログラムでメモリを解放せずに割り当て続けると、実行時に領域が不足する可能性があります。

ブロックの開始時点で配列や文字列のサイズがわからず、実行時に決定する必要があるアプリケーションでは、ALLOCATE 文で基底付き変数を使用すると便利です。また、基底付き変数の割り当ては、グラフ構造のノードを動的に作成する手段としても使用できます (ポインターでリンクしてリスト構造やツリー構造を生成できます)。ベース構造体の例については、「ブロックの有効化および再帰」のセクションを参照してください。

予期しない副作用を防ぎ、プログラムを読みやすくするために、基底付き変数の範囲は可能な限り定数値にすることをお勧めします。範囲を可変にする必要がある場合も、同じ理由から、基底付き変数の宣言で範囲の式を使用しないことをお勧めします。基底付き変数のサイズは、その変数を参照するたびに評価されます。