派生型として知られる追加のデータ型は、組み込みデータ型や他の派生型から作成することができます。派生型の名前 (type_name)、データ型、および派生型のコンポーネントの名前を定義するには、タイプ定義が必要です。
+----------------------------------IBM 拡張----------------------------------+
レコード構造は、集合非配列データの操作でよく使用される拡張機能です。 Fortran 90 では、レコード構造は派生型よりも前に導入されました。
レコード構造で使用される構文は、多くの場合 Fortran 派生型で使用される構文に似ています。また、多くの場合、これらの 2 つの機能のセマンティクスも類似しています。このため、XL Fortran では、これらの 2 つの機能をほぼ完全に交換できるような方法でレコード構造がサポートされています。そのため、以下のようになります。
ただし、以下の違いがあります。
+--------------------------------IBM 拡張の終り-------------------------------+
>>-DERIVED_TYPE_statement-------------------------------------->< >>-+------------------------+---------------------------------->< '-PRIVATE_SEQUENCE_block-' >>-component_def_stmt_block------------------------------------>< >>-END_TYPE_statement------------------------------------------>< |
+---------------------------------Fortran 95---------------------------------+
さらに、Fortran 95 では、派生型の定義の各コンポーネントに対して、デフォルトの初期化を指定することができます。詳細な構文および説明に関しては、 タイプ宣言を参照してください。
+------------------------------Fortran 95 の終り------------------------------+
+---------------------------------Fortran 95---------------------------------+
Fortran 95 では派生型の直接コンポーネントには、次のものがあります。
+------------------------------Fortran 95 の終り------------------------------+
各派生型は、組み込みデータ型の最終コンポーネントとして解決されるか、あるいは割り当て可能またはポインターになります。
このタイプ名は、ローカル・エンティティーです。これは、どの組み込みデータ型とも同じ名前にすることはできません。ただし、BYTE および DOUBLE COMPLEX は例外です。
END TYPE ステートメントには、TYPE ステートメントで指定したものと同じ type_name をオプションで指定することができます。
派生型のコンポーネントでは、どの組み込みデータ型でも指定することができます。また、コンポーネントは、事前に定義された派生型の 1 つであってもかまいません。ポインター・コンポーネントは、そのコンポーネントの同じ派生データ型であってもかまいません。コンポーネントの名前は、派生型内では固有でなければなりませんが、派生型定義の有効範囲外の名前と異なっていてもかまいません。 CHARACTER タイプとして宣言されたコンポーネントは、定数宣言式である長さ指定を含んでいる必要があります。アスタリスクは、長さ指定子として使用できません。ポインター以外の配列コンポーネントは、定数次元宣言子で宣言しなければなりません。ポインター配列コンポーネントは、deferred_shape_spec_list で宣言しなければなりません。
デフォルトでは、記憶順序は、コンポーネントの定義順序に暗黙指定されません。ただし、SEQUENCE ステートメントを指定すると、派生型は、順序派生型 になります。順序派生型では、コンポーネントの順序に従って、この派生型で宣言されたオブジェクトの記憶順序が指定されます。順序派生型のコンポーネントが派生型の場合、その派生型も順序派生型でなければなりません。
順序派生型のサイズは、その派生型のすべてのコンポーネントを保持するために必要なストレージのバイト数に等しくなります。
順序派生型を使用すると、データの並びが揃わなくなることがあります。これは、プログラムのパフォーマンスに悪影響を与えます。
PRIVATE ステートメントは、派生型がモジュールの指定部分内で定義された場合にのみ、指定することができます。派生型のコンポーネントがプライベートと宣言されるタイプの場合、派生型の定義で PRIVATE ステートメントを指定するか、または派生型自体がプライベートでなければなりません。
タイプ定義がプライベートである場合、次のものは、定義するモジュール内でのみアクセス可能となります。
派生型の定義に、PRIVATE ステートメントが含まれている場合、その派生型が public であっても、そのコンポーネントは、定義するモジュール内でのみアクセスできます。構造体コンポーネントは、定義するモジュール内でのみ使用できます。
派生型オブジェクトのコンポーネントは、オブジェクトのいずれかの最終コンポーネントが I/O ステートメントの有効範囲の単位でアクセスできない場合、 I/O リスト項目として指定することはできません。派生型オブジェクトは、ポインターまたは割り当て可能であるコンポーネントを持っている場合、データ転送ステートメント内に指定することはできません。
派生型のスカラー・エンティティーは、 構造体 と呼ばれます。順序派生型のスカラー・エンティティーは、 順序構造体 と呼ばれます。構造体のタイプ指定子は、TYPE キーワードを含み、その後に括弧で囲まれた派生型の名前が続きます。指定した派生型のエンティティー宣言に関する詳細は、 TYPEを参照してください。構造体のコンポーネントは、構造体コンポーネント と呼ばれます。 構造体コンポーネント は、構造体の 1 つのコンポーネントであるか、派生型の配列を成しているコンポーネントです。
private 派生型のオブジェクトは、定義するモジュールの外部で使用することはできません。
デフォルトの初期化は、等号の後ろに初期化式を付けるか、またはスラッシュで囲まれた initial_value_list を使用して指定できます。現在、この形式の初期化は、レコード構造宣言または標準の派生型宣言を使用して宣言されたコンポーネントでサポートされています。
+---------------------------------Fortran 95---------------------------------+
Fortran 95 で、デフォルトの初期化の候補となるデータ・オブジェクトは、以下のような名前付きデータ・オブジェクトです。
非ポインター・コンポーネントのデフォルトの初期化は、そのタイプの直接コンポーネントに対して行われるどのデフォルト初期化よりも優先します。
仮引き数に INTENT(OUT) が指定されているものが、デフォルトの初期化がされている派生型である場合、それを想定サイズ配列にすることはできません。非ポインター・オブジェクトまたはサブオブジェクトがタイプ定義内でデフォルトの初期化を指定されている場合、それを DATA ステートメントによって初期化することはできません。
+------------------------------Fortran 95 の終り------------------------------+
デフォルトの初期化付きの派生型のデータ・オブジェクトは、 IBM 拡張として共通ブロックの中に指定できます。また、XL Fortran ではデフォルトの初期化は、 -qsave=defaultinit が指定されていない限り、SAVE 属性を暗黙指定しません。
+---------------------------------Fortran 95---------------------------------+
明示的な初期化とは異なり、コンポーネントのデフォルトの初期化を有効にするために、データ・オブジェクトに SAVE 属性を指定する必要はありません。デフォルトの初期化は、派生型のいくつかのコンポーネントに対して指定することができますが、すべてのコンポーネントに指定する必要はありません。
ストレージに関連した記憶単位のデフォルトの初期化を指定することができます。ただし、デフォルトの初期化を提供するデフォルトのオブジェクトまたはサブオブジェクトは、同じタイプでなければなりません。そのオブジェクトまたはサブオブジェクトは、同じ型付きパラメーターを持たなければならず、記憶単位に同じ値を提供しなければなりません。
直接コンポーネントは、タイプ定義内で対応するコンポーネント定義に対してデフォルトの初期化を指定していれば、コンポーネントへのアクセス可能性に関係なく、初期値を受け取ることになります。
デフォルトの初期化の対象になるデータ・オブジェクトの場合、その非ポインター・コンポーネントは、最初に定義されているか、または対応するデフォルトの初期化式によって定義されます。そのポインター・コンポーネントは、最初に関連解除されているか、または以下の条件のいずれかが満たされる場合は、関連解除されます。
コンポーネントに対するデフォルトの初期化を指定した派生型のオブジェクトの割り振りによって、コンポーネントは以下のようになります。
ENTRY ステートメントを持つサブプログラムでは、デフォルトの初期化は、参照されるプロシージャー名の引き数リストにある仮引き数の場合だけ実行されます。この種の仮引き数に OPTIONAL 属性がある場合、デフォルトの初期化はこの仮引き数がある場合に限り実行されます。
デフォルトの初期化が指定された派生型のモジュール・データ・オブジェクトが、デフォルト初期化の候補のデータ・オブジェクトである場合には、 SAVE 属性がなければなりません。
+------------------------------Fortran 95 の終り------------------------------+
標準の派生型宣言を使用して宣言された順次派生型のサイズは、その派生型のすべてのコンポーネントを保持するために必要なバイト数の合計と等しくなります。
レコード構造宣言を使用して宣言された順序派生型のサイズは、その派生型のコンポーネントおよび埋め込みのすべてを保持するために必要なバイト数の合計と等しくなります。
以前は、共通ブロックにある数値順序または文字順序の構造体は、そのコンポーネントが共通ブロック内で直接列挙されているかのように処理されていました。現在は、これは、標準の派生型宣言を使用して宣言されたタイプの構造体にのみ適用されます。
名前リスト入力では、構造はその非充てん最終コンポーネントのリストに展開されます。
名前リスト出力では、構造はその非充てん最終コンポーネントの値に展開されます。
定様式データ転送ステートメント (READ、WRITE、または PRINT) では、%FILL コンポーネントではない派生型のエンティティーのコンポーネントのみが input-item-list または output-item-list に指定されているかのように処理されます。
派生型のエンティティー内の %FILL フィールドは、定様式データ転送ステートメントでは埋め込みとして扱われます。
2 つのデータ・オブジェクトを、同じ派生型定義を参照することによって宣言している場合には、これらのデータ・オブジェクトの派生型は同じです。
これらのデータ・オブジェクトが別々の有効範囲単位内にある場合は、両者が同じ派生型を持つことができます。次の条件が満たされる場合は、ホスト関連付けまたは使用関連付けを介して派生型定義にアクセスできるか、またはデータ・オブジェクトが自己の派生型定義を参照します。
SEQUENCE を指定する派生型定義は、プライベートと宣言される定義、あるいはプライベートであるコンポーネントを持つ定義とは異なります。
PROGRAM MYPROG TYPE NAME ! Sequence derived type SEQUENCE CHARACTER(20) LASTNAME CHARACTER(10) FIRSTNAME CHARACTER(1) INITIAL END TYPE NAME TYPE (NAME) PER1 CALL MYSUB(PER1) PER1 = NAME('Smith','John','K') ! Structure constructor CALL MYPRINT(PER1) CONTAINS SUBROUTINE MYSUB(STUDENT) ! Internal subroutine MYSUB TYPE (NAME) STUDENT ! NAME is accessible via host association ... END SUBROUTINE MYSUB END SUBROUTINE MYPRINT(NAMES) ! External subroutine MYPRINT TYPE NAME ! Same type as data type in MYPROG SEQUENCE CHARACTER(20) LASTNAME CHARACTER(10) FIRSTNAME CHARACTER(1) INITIAL END TYPE NAME TYPE (NAME) NAMES ! NAMES and PER1 from MYPROG PRINT *, NAMES ! have the same data type END SUBROUTINE
MODULE MOD STRUCTURE /S/ INTEGER I INTEGER, POINTER :: P END STRUCTURE RECORD /S/ R END MODULE PROGRAM P USE MOD, ONLY: R STRUCTURE /S/ INTEGER J INTEGER, POINTER :: Q END STRUCTURE RECORD /S/ R2 R = R2 ! OK - same type name, components have same attributes and ! type (but different names) END PROGRAM P
構造体コンポーネントは、派生型も含めどの明示タイプでもかまいません。
コンポーネント指定子 を使って特定の構造体コンポーネントを参照することもできます。スカラー・コンポーネント指定子は次のような構文を持ちます。
scalar_struct_comp:
>>-name--+---------------------+--------------------------------> '-(--int_expr_list--)-' >--+--------------------------------------------------+---------> | .----------------------------------------------. | | V | | '---separator comp_name--+---------------------+-+-' '-(--int_expr_list--)-' >--separator comp_name-+---------------------+----------------->< '-(--int_expr_list--)-' |
構造体コンポーネントは、最右端の comp_name と同様のタイプ、型付きパラメーター、POINTER 属性 (もしあれば) を持ちます。構造体コンポーネントは、親オブジェクトから INTENT、TARGET、PARAMETER などの属性を継承します。
注:
名前リストのフォーマット設定では、区切り文字はパーセント記号でなければなりません。
区切り文字としてピリオドを使用する構造体コンポーネントであるか、または 2 進演算であるかのいずれにでも解釈される形式が式に入っており、その名前の演算子が有効範囲単位内でアクセス可能な場合、 XL Fortran はその式を 2 進演算として処理します。それが意図した解釈ではない場合は、パーセント記号を使用してその部分への参照を解除するか、または、自由ソース形式であれば、ピリオドと comp_name の間に空白を挿入してください。
例 1: 区切り文字としてのピリオドのあいまいな使用
MODULE MOD STRUCTURE /S1/ STRUCTURE /S2/ BLUE INTEGER I END STRUCTURE END STRUCTURE INTERFACE OPERATOR(.BLUE.) MODULE PROCEDURE BLUE END INTERFACE CONTAINS INTEGER FUNCTION BLUE(R1, I) RECORD /S1/ R1 INTENT(IN) :: R1 INTEGER, INTENT(IN) :: I BLUE = R1%BLUE%I + I END FUNCTION BLUE END MODULE MOD PROGRAM P USE MOD RECORD /S1/ R1 R1%BLUE%I = 17 I = 13 PRINT *, R1.BLUE.I ! Calls BLUE(R1,I) - prints 30 PRINT *, R1%BLUE%I ! Prints 17 END PROGRAM P
例 2: 区切り文字の混合
STRUCTURE /S1/ INTEGER I END STRUCTURE STRUCTURE /S2/ RECORD /S1/ C END STRUCTURE RECORD /S2/ R R.C%I = 17 ! OK R%C.I = 3 ! OK R%C%.I = 13 ! OK R.C.I = 19 ! OK END
例 3: 派生型でのパーセントとピリオドの機能
STRUCTURE /S/ INTEGER I, J END STRUCTURE TYPE DT INTEGER I, J END TYPE DT RECORD /S/ R1 TYPE(DT) :: R2 R1.I = 17; R1%J = 13 R2.I = 19; R2%J = 11 END
+----------------------------------IBM 拡張----------------------------------+
ポインター・コンポーネントと同様、割り振り可能コンポーネントは最終コンポーネントとして定義されます。これは、値 (存在する場合) が残りの構造とは別に保管され、構造の作成時にはこのストレージが存在しない (オブジェクトが割り振り解除されているため) ためです。最終ポインター・コンポーネントと同様、最終割り振り可能コンポーネントを含む変数は入出力リストに直接入れることは禁じられています。入出力の割り振り可能コンポーネントまたはポインター・コンポーネントは、ユーザーがリストします。
現在、割り振り可能配列と同様に、割り振り可能コンポーネントはストレージ関連付けコンテキストを禁じられています。このため、最終割り振り可能コンポーネントを含む変数は、 COMMON または EQUIVALENCE には入れることができません。ただし、SEQUENCE タイプには割り振り可能コンポーネントが許可されており、同じタイプを複数の有効範囲単位に別個に定義することが許されます。
最終割り振り可能コンポーネントを含む変数を割り振り解除すると、現在割り振られている変数の割り振り可能コンポーネントがすべて自動的に割り振り解除されます。
割り振り可能コンポーネントを含む派生型の構造コンストラクターでは、割り振り可能コンポーネントに対応する式は以下のいずれかでなければなりません。
割り振り可能コンポーネントを含む派生型のオブジェクトの組み込み割り当ての場合、左側にある変数の割り振り可能コンポーネントは、割り振り状況と、割り振り済みである場合は式の対応するコンポーネントの境界と値を受け取ります。これは、次の順序でステップが実行されたかのように行われます。
INTENT(OUT) 仮引き数に関連した実引き数の割り振り済み最終割り振り可能コンポーネントはプロシージャーに入るときに割り振り解除されるので、仮引き数の対応するコンポーネントは、現在割り振り済みでないという割り振り状況を持つようになります。
これにより、変数の割り振り可能コンポーネントの前の内容を指し示すポインターが、確実に未定義になります。
MODULE REAL_POLYNOMIAL_MODULE TYPE REAL_POLYNOMIAL REAL, ALLOCATABLE :: COEFF(:) END TYPE INTERFACE OPERATOR(+) MODULE PROCEDURE RP_ADD_RP, RP_ADD_R END INTERFACE CONTAINS FUNCTION RP_ADD_R(P1,R) TYPE(REAL_POLYNOMIAL) RP_ADD_R, P1 REAL R INTENT(IN) P1,R ALLOCATE(RP_ADD_R%COEFF(SIZE(P1%COEFF))) RP_ADD_R%COEFF = P1%COEFF RP_ADD_R%COEFF(1) = P1%COEFF(1) + R END FUNCTION FUNCTION RP_ADD_RP(P1,P2) TYPE(REAL_POLYNOMIAL) RP_ADD_RP, P1, P2 INTENT(IN) P1, P2 INTEGER M ALLOCATE(RP_ADD_RP%COEFF(MAX(SIZE(P1%COEFF), SIZE(P2%COEFF)))) M = MIN(SIZE(P1%COEFF), SIZE(P2%COEFF)) RP_ADD_RP%COEFF(:M) = P1%COEFF(:M) + P2%COEFF(:M) IF (SIZE(P1%COEFF)>M) THEN RP_ADD_RP%COEFF(M+1:) = P1%COEFF(M+1:) ELSE IF (SIZE(P2%COEFF)>M) THEN RP_ADD_RP%COEFF(M+1:) = P2%COEFF(M+1:) END IF END FUNCTION END MODULE PROGRAM EXAMPLE USE REAL_POLYNOMIAL_MODULE TYPE(REAL_POLYNOMIAL) P, Q, R P = REAL_POLYNOMIAL((/4,2,1/)) ! Set P to (X**2+2X+4) Q = REAL_POLYNOMIAL((/1,1/)) ! Set Q to (X+1) R = P + Q ! Polynomial addition PRINT *, 'Coefficients are: ', R%COEFF END
+--------------------------------IBM 拡張の終り-------------------------------+
>>-type_name--(--expr_list--)---------------------------------->< |
構造体コンストラクターによって、値の番号付きリストから派生型のスカラー値を構成することができます。構造体コンストラクターは、参照される派生型の定義の前に指定できません。
expr_list には、派生型のコンポーネントごとに 1 つの値が含まれています。 expr_list の式の順序は、数および順序の点で派生型のコンポーネントと一致していなければなりません。それぞれの式のタイプと型付きパラメーターは、対応するコンポーネントのタイプおよび型付きパラメーターと整合性のある割り当てになっている必要があります。データ型は、必要に応じて変換されます。
ポインターであるコンポーネントは、ポインターのコンポーネントと同じタイプで宣言できます。構造体コンストラクターがポインターを含む派生型に対して作成された場合、ポインター・コンポーネントに対応する式は、ポインター割り当てステートメント内のそのようなポインターのために使用可能なターゲットとなり得るオブジェクトに対して評価を行わなければなりません。
+----------------------------------IBM 拡張----------------------------------+
派生型のコンポーネントが割り振り可能な場合、対応するコンストラクター式は、引き数なしの組み込み関数 NULL() への参照になるか、割り振り可能エンティティーになるか、あるいは対応するコンストラクター式の評価の結果が同じランクのエンティティーになります。式が組み込み関数 NULL() への参照の場合、コンストラクターの対応するコンポーネントは、現在割り振り済みでないという状況を持ちます。式が割り振り可能エンティティーの場合、コンストラクターの対応するコンポーネントは、割り振り可能エンティティーと同じ割り振り状況を持ち、 割り振り済みである場合は、同じ境界 (もしあれば) と値も持ちます。そうでない場合は、コンストラクターの対応するコンポーネントは、現在割り振り済みであるという割り振り状況と、式と同じ境界 (もしあれば) および値を持ちます。
レコード構造宣言を使用するコンポーネントが %FILL の場合、そのタイプの構造コンストラクターは使用できません。
派生型が有効範囲単位内でアクセス可能であり、有効範囲単位内でアクセス可能な同じ名前の派生型ではないクラス 1 のローカル・エンティティーがある場合、そのタイプの構造コンストラクターをその有効範囲内で使用することはできません。
+--------------------------------IBM 拡張の終り-------------------------------+
例 1:
MODULE PEOPLE TYPE NAME SEQUENCE ! Sequence derived type CHARACTER(20) LASTNAME CHARACTER(10) FIRSTNAME CHARACTER(1) INITIAL END TYPE NAME TYPE PERSON ! Components accessible via use ! association INTEGER AGE INTEGER BIRTHDATE(3) ! Array component TYPE (NAME) FULLNAME ! Component of derived type END TYPE PERSON END MODULE PEOPLE
PROGRAM TEST1 USE PEOPLE TYPE (PERSON) SMITH, JONES SMITH = PERSON(30, (/6,30,63/), NAME('Smith','John','K')) ! Nested structure constructors JONES%AGE = SMITH%AGE ! Component designator CALL TEST2 CONTAINS SUBROUTINE TEST2 TYPE T INTEGER EMP_NO CHARACTER, POINTER :: EMP_NAME(:) ! Pointer component END TYPE T TYPE (T) EMP_REC CHARACTER, TARGET :: NAME(10) EMP_REC = T(24744,NAME) ! Pointer assignment occurs END SUBROUTINE ! for EMP_REC%EMP_NAME END PROGRAM
+---------------------------------Fortran 95---------------------------------+
例 2:
PROGRAM LOCAL_VAR TYPE DT INTEGER A INTEGER :: B = 80 END TYPE TYPE(DT) DT_VAR ! DT_VAR%B IS INITIALIZED END PROGRAM LOCAL_VAR
例 3:
MODULE MYMOD TYPE DT INTEGER :: A = 40 INTEGER, POINTER :: B => NULL() END TYPE END MODULE PROGRAM DT_INIT USE MYMOD TYPE(DT), SAVE :: SAVED(8) ! SAVED%A AND SAVED%B ARE INITIALIZED TYPE(DT) LOCAL(5) ! LOCAL%A LOCAL%B ARE INITIALIZED END PROGRAM
+------------------------------Fortran 95 の終り------------------------------+
+----------------------------------IBM 拡張----------------------------------+
レコード構造を宣言すると、標準の FORTRAN 派生型定義でユーザー定義タイプを宣言するのと同じ方法でユーザー定義タイプが宣言されます。 レコード構造宣言を使用して宣言されたタイプは派生型です。多くの場合、標準の FORTRAN 構文を使用して宣言された派生型に適用される規則は、レコード構造構文を使用して宣言された派生型に適用されます。規則に違いがある場合、レコード構造宣言を使用して宣言された派生型と、標準の派生型宣言を使用して宣言された派生型の両者を参照するとその違いがわかります。
レコード構造宣言は、以下の構文に従って行います。
record_structure_dcl:
>>-structure_stmt---------------------------------------------->< .----------------------. V | >>---struct_comp_dcl_item-+------------------------------------>< >>-end_structure_stmt------------------------------------------>< |
struct_comp_dcl_item:
>>-+-component_def_stmt---+------------------------------------>< +-record_structure_dcl-+ '-parameter_stmt-------'
component_def_stmt は、派生型のコンポーネントを定義するために使用されるタイプ宣言ステートメントです。
structure_stmt:
>>-STRUCTURE--+------------------+--+--------------------+----->< '-/structure_name/-' '-component_dcl_list-'
component_dcl:
>>-a--+----------------+--------------------------------------->< '-(-array_spec-)-'
a はオブジェクト名です。
構造ステートメントは、それを囲む最も近いプログラム単位、インターフェース本体、またはサブプログラムの有効範囲単位内の派生型として、structure_name を宣言します。派生型は、その有効範囲単位内のクラス 1 のローカル・エンティティーです。
構造ステートメントは別のレコード構造宣言内にネストされない限り、 component_dcl_list は指定されません。同様に構造ステートメントの structure_name は、別のレコード構造宣言内にネストされている record_structure_dcl の一部でない限り省略できません。 record_structure_dcl は、少なくとも 1 つのコンポーネントを持っている必要があります。
レコード構造宣言を使用して宣言された派生型は、順序派生型であり、順序派生型に適用されるすべての規則に従います。標準派生型宣言を使用して宣言された順序派生型と同様に、 レコード構造宣言を使用して宣言されたタイプのコンポーネントは、非順序派生型にできません。 レコード構造宣言には、PRIVATE または SEQUENCE ステートメントを入れることはできません。
レコード構造宣言は有効範囲単位を定義します。 record_structure_dcl にあるすべてのステートメントは、レコード構造宣言の有効範囲単位の中に入ります (record_structure_dcl に含まれているその他の record_structure_dcl は例外)。これらの規則は、標準の派生型宣言にも当てはまります。明確にするために、以下で繰り返して説明します。
record_structure_dcl 内の parameter_stmt は、それを囲む最も近いプログラム単位、インターフェース本体、またはサブプログラムの有効範囲単位内にある名前付き定数を宣言します。このような parameter_stmt で宣言された名前付き定数は、この定数を含む record_structure_dcl で宣言されたコンポーネントと同じ名前にできます。
structure_stmt で宣言されたコンポーネントはどれも、それを囲む派生型のコンポーネントであり、それを囲む構造の有効範囲単位のローカル・エンティティーです。このようなコンポーネントのタイプは、その structure_stmt で宣言される派生型です。
標準の派生型宣言を使用して宣言された派生型とは異なり、 レコード構造宣言を使用して宣言された派生型名は、組み込みタイプの名前と同じ名前にできます。
レコード構造宣言の component_def_stmt には、コンポーネントの名前の代わりに %FILL を使用できます。 %FILL コンポーネントは、レコード構造宣言において、データを希望する位置に合わせるためのプレースホルダーとして使用されます。初期化では、%FILL コンポーネントに関する指定はできません。 レコード構造宣言内の %FILL の各インスタンスは、タイプに指定したその他のすべてのコンポーネント名と異なり、しかもその他のすべての %FILL コンポーネントとも異なる、固有のコンポーネント名として扱われます。 %FILL は 1 つのキーワードであり、-qmixed コンパイラー・オプションの影響は受けません。
名前を持たない、ネストされた構造の各インスタンスは、他のすべてのアクセス可能エンティティーの名前とは異なる固有の名前を持っているものとして扱われます。
派生型についてこれまで説明した規則の延長として、レコード構造宣言を使用して宣言された派生型の直接コンポーネントには、次のものがあります。
派生型の非充てん最終コンポーネントは派生型の最終コンポーネントであり、直接コンポーネントでもあります。
以前は、デフォルトの初期化が行われる派生型のオブジェクトを共通ブロックに入れることはできませんでした。現在は、これは拡張機能として可能になりました。ただし、共通ブロックの初期化が、複数の有効範囲単位内で行われることがないようにする必要があります。
例 1: ネストされたレコード構造宣言 - 名前付きおよび名前なし
STRUCTURE /S1/ STRUCTURE /S2/ A ! A is a component of S1 of type S2 INTEGER I END STRUCTURE STRUCTURE B ! B is a component of S1 of unnamed type INTEGER J END STRUCTURE END STRUCTURE RECORD /S1/ R1 RECORD /S2/ R2 ! Type S2 is accessible here. R2.I = 17 R1.A = R2 R1.B.J = 13 END
例 2: 構造宣言内でネストされているパラメーター・ステートメント
INTEGER I STRUCTURE /S/ INTEGER J PARAMETER(I=17, J=13) ! Declares I and J in scope of program unit to ! be named constants END STRUCTURE INTEGER J ! Confirms implicit typing of named constant J RECORD /S/ R R.J = I + J PRINT *, R.J ! Prints 30 END
例 3: %FILL フィールド
STRUCTURE /S/ INTEGER I, %FILL, %FILL(2,2), J STRUCTURE /S2/ R1, %FILL, R2 INTEGER I END STRUCTURE END STRUCTURE RECORD /S/ R PRINT *, LOC(R%J)-LOC(R%I) ! Prints 24 with -qintsize=4 PRINT *, LOC(R%R2)-LOC(R%R1) ! Prints 8 with -qintsize=4 END
レコード構造宣言を使用して宣言された派生型は、順序派生型です。このようなタイプのオブジェクトのコンポーネントは指定された順序でメモリーに保管されます。標準の派生型宣言を使用して宣言された順序派生型のオブジェクトについてもこれと同じことが言えます。
-qalign オプションは、ストレージ内でのデータ・オブジェクトの位置合わせを指定します。これにより、誤って位置合わせされたデータによるパフォーマンス上の問題が回避されます。 [no]4k と struct の両方のサブオプションを指定でき、相互に排他的ではありません。デフォルトの設定は -qalign=no4k:struct=natural です。 [no]4K は、主に、論理ボリューム入出力とディスク・ストライピングの組み合わせで役に立ちます。
+--------------------------------IBM 拡張の終り-------------------------------+
+----------------------------------IBM 拡張----------------------------------+
UNION は、囲まれたレコード構造の中に、プログラム内のデータ域を共有できるフィールド・グループを宣言します。
UNION および MAP は次の構文に従います。
union_dcl:
.----------------. V | >>-UNION----union_dcl_item-+----------------------------------->< >>-END UNION--------------------------------------------------->< |
union_dcl_item:
>>-+-map_dcl--------+------------------------------------------>< '-parameter_stmt-'
map_dcl:
.--------------. V | >>-MAP----map_dcl_item-+--------------------------------------->< >>-END MAP----------------------------------------------------->< |
map_dcl_item:
>>-+-struct_comp_dcl_item-+------------------------------------>< '-record_stmt----------'
struct_comp_dcl_item:
>>-+-component_def_stmt---+------------------------------------>< +-record_structure_dcl-+ +-parameter_stmt-------+ '-union_dcl------------'
UNION 宣言はレコード構造内に定義する必要があり、 MAP 宣言の中に入れることが可能です。また、MAP 宣言は UNION 宣言内になければなりません。 UNION 宣言内の map_dcl_item にあるすべての宣言は、宣言がどの map_dcl にあるのかにかかわらず同じネスト・レベルになっていなければなりません。このため、map_dcl 内のコンポーネント名を、同じレベルの他の map_dcl に入れることができません。
MAP 宣言内で宣言されるコンポーネントには POINTER または ALLOCATABLE 属性があってはいけません。
UNION MAP を持つレコード構造は I/O ステートメントには使用できません。
MAP 宣言で宣言されたコンポーネントは、UNION 構造体内のその他の MAP 宣言で宣言されたコンポーネントと同じストレージを共用します。ある MAP 宣言内にある 1 つのコンポーネントに値を割り当てると、ストレージをこのコンポーネントと共用する、その他の MAP 宣言内のコンポーネントが影響を受けます。
MAP のサイズは、MAP 内で宣言されたコンポーネントの合計サイズです。
UNION 宣言で確立されるデータ域のサイズは、その UNION で定義された最大 MAP のサイズです。
MAP 宣言または UNION 構造体にある parameter_stmt は、最も近いこれを囲むプログラム単位、インターフェース本体、またはサブプログラムの有効範囲単位内でエンティティーを宣言します。
MAP 宣言にある %FILL フィールドは、レコード構成で目的に合ったデータの位置合わせを行うためのプレースホルダーとして使用されます。その他の非充てんコンポーネント、またはデータ域を %FILL フィールドと共用するその他の map 宣言内のコンポーネントの部分は未定義です。
UNION 宣言内の少なくとも 1 つの MAP にある component_def_stmts にデフォルトの初期化が指定されている場合、初期化の最後のオカレンスがコンポーネントの最終初期化になります。
レコード構造内の UNION MAP 宣言のいずれかにデフォルトの初期化が指定されている場合、デフォルトで割り当てられたストレージ・クラスを持つタイプの変数には、以下のいずれかのストレージ・クラスが与えられます。
常に 1 つの MAP のみが共用ストレージに関連付けられます。別の MAP からのコンポーネントが参照される場合、関連した MAP が関連解除され、そのコンポーネントは未定義になります。これで、参照されている MAP がストレージに関連させられます。
map_dcl のコンポーネントが UNION 内のその他の map_dcl の %FILL コンポーネントに完全にまたは部分的にマップされている場合、そのコンポーネントがデフォルトの初期化か、または割り当てステートメントによって初期化されない限り、オーバーラップ部分の値は未定義です。
例 1: UNION のサイズは、その UNION 内の最大 MAP のサイズと同じです
structure /S/ union map integer*4 i, j, k real*8 r, s, t end map map integer*4 p, q real*4 u, v end map end union ! Size of the union is 36 bytes. end structure record /S/ r
例 2: 別の -qsave オプションおよびサブオプションを使用すると、UNION MAP の結果は異なります
PROGRAM P CALL SUB CALL SUB END PROGRAM P SUBROUTINE SUB LOGICAL, SAVE :: FIRST_TIME = .TRUE. STRUCTURE /S/ UNION MAP INTEGER I/17/ END MAP MAP INTEGER J END MAP END UNION END STRUCTURE RECORD /S/ LOCAL_STRUCT INTEGER LOCAL_VAR IF (FIRST_TIME) THEN LOCAL_STRUCT.J = 13 LOCAL_VAR = 19 FIRST_TIME = .FALSE. ELSE ! Prints " 13" if compiled with -qsave or -qsave=all ! Prints " 13" if compiled with -qsave=defaultinit ! Prints " 17" if compiled with -qnosave PRINT *, LOCAL_STRUCT%j ! Prints " 19" if compiled with -qsave or -qsave=all ! Value of LOCAL_VAR is undefined otherwise PRINT *, LOCAL_VAR END IF END SUBROUTINE SUB
例 3: UNION 構造内の MAP 宣言にあるデフォルトの初期化の最後のオカレンスは、コンポーネントの最終初期化になります
structure /st/ union map integer i /3/, j /4/ union map integer k /8/, l /9/ end map end union end map map integer a, b union map integer c /21/ end map end union end map end union end structure record /st/ R print *, R.i, R.j, R.k, R.l ! Prints "3 4 21 9" print *, R.a, R.b, R.c ! Prints "3 4 21" end
例 4: 次のプログラムは -qintsize=4 および -qalign=struct=pack でコンパイルされます。 UNION MAP 内のコンポーネントは位置合わせされてパックされます
structure /s/ union map integer*2 i /z'1a1a'/, %FILL, j /z'2b2b'/ end map map integer m, n end map end union end structure record /s/ r print '(2z6.4)', r.i, r.j ! Prints "1A1A 2B2B" print '(2z10.8)', r.m, r.n ! Prints "1A1A0000 2B2B0000" however ! the two bytes in the lower order are ! not guaranteed. r.m = z'abc00cba' ! Components are initialized by ! assignment statements. r.n = z'02344320' print '(2z10.8)', r.m, r.n ! Prints "ABC00CBA 02344320" print '(2z6.4)', r.i, r.j ! Prints "ABC0 0234" end
+--------------------------------IBM 拡張の終り-------------------------------+