![]() | パフォーマンスの最適化 | 拡張言語機能 | ![]() |
この章では、プログラムの呼び出し方法について説明します。副プログラムの作成方法と、副プログラム間でのパラメータの受け渡し方法に関する情報を記載しています。
Server Express では、1 つのアプリケーションをソースレベルでいくつかのプログラムに分けて開発することが可能です。これらのプログラムはメインプログラムと複数の副プログラムから構成され、各副プログラムはメインプログラムから動的に呼び出すことができます。図 2-1 は、このスタイルで開発したアプリケーションの構成を示しています。
メインプログラム A はアプリケーションの起動から終了までメモリに常駐し、副プログラム B、C、H を呼び出します。これらの副プログラム側では、次の呼び出しが実行されます。
B | D、E、F の呼び出し |
C | X、Y、Z、L、K の呼び出し |
H | K の呼び出し |
K | M、N、O の呼び出し |
B、C、および H はメインプログラムから独立しているため、メモリに常駐させる必要はありません。これらの副プログラムは、必要なときに同じ物理メモリを使用して呼び出すことができます。下位の副プログラムについても、これは同様です。
図中の K のように使用頻度の高い副プログラムが存在する場合には、ロードに伴う遅延を避けるためにも、CALL と CANCEL を正しく活用し、その副プログラムをメモリに常駐させる必要があります。ただし、K は副プログラム、 C (または H) から呼び出されるため、C や H がメモリに格納されていないと呼び出せません。また、プログラムによるオーバーフローが発生する可能性もあります。X や Y、Z のレベルは、下位の副プログラムが存在しないため、どのような順序でも呼び出すことができます。
副プログラムを呼び出した後、そのままメモリに保持すると、呼び出すたびにファイルを開く手間が省けます。ファイルを開いた状態でメモリに保持するには、EXIT 文を使用します。CANCEL 文を実行すると、メモリに保持していたファイルが閉じられ、対応する副プログラムによって占有されていたメモリ領域が解放されます。ただし、同じファイル内の他の副プログラムを呼び出した場合には、その副プログラムもキャンセルする必要があります。
次のサンプルコードは、上図のような独立した副プログラムのツリー構造内で、下位の副プログラムを動的に呼び出す方法を示しています。
working-storage section. 01 next-prog pic x(20) value spaces. 01 current-prog pic x(20) value "rstprg". procedure division. loop. call current-prog using next-prog cancel current-prog if next-prog = spaces stop run end-if move next-prog to current-prog move spaces to next-prog go to loop.
呼び出される副プログラムを次に示します。
. . . . . . linkage-section. 01 next-prog pic x(20). . . .
. . . procedure division using next-prog. . . . . . . move "follow" to next-prog. exit program.
このように、各副プログラム (独立区分) は自身をキャンセルして CALL 文内の名前を変更し、USING 指定を使用して下位の副プログラムを呼び出します。
1 つの呼び出しでメモリにロードできるプログラムの数には、特に上限はありません。この数はコンピュータに搭載しているメモリの容量と、呼び出される副プログラムのサイズによって左右されます。
副プログラムの動的な呼び出しは、呼び出された副プログラムをキャンセルすると、対応するメモリ領域もクリアされる点で、副プログラムを 1 つの実行ファイルに静的にリンクする方法よりも優れています。
呼び出しに応じて動的にロードされた各副プログラムは、ファイル名で識別されます。一方、静的にリンクされた副プログラムの識別には PROGRAM-ID 段落が使用できます。詳細については、『COBOL 副プログラムの呼び出し』を参照してください。
PROGRAM-ID 段落内の program-name の値として拡張子なしのファイル名を使用すると、プログラムが見つからない場合に生成される program not found エラーの発生率が確実に低下します。この方法は、アプリケーション開発で静的および動的に呼び出される副プログラムのどちらを使用しても実行プログラムを構築することができます。
PROGRAM-ID 段落の詳細については、『言語リファレンス』を参照してください。
サブプログラムとメインプログラムは、COBOL のほか C などの言語でも開発できます。異なる言語で開発した複数のサブプログラムを 1 つのアプリケーションで併用することも可能です。ただし、COBOL 以外の言語で開発したサブプログラムを COBOL で開発したプログラムから呼び出すには、サブプログラムを動的ロード用のランタイムサポートモジュール (ダイナミックローダ) にリンクする、または、静的または動的にリンクされた COBOL アプリケーションにリンクする必要があります。
COBOL で開発した副プログラムはリンクすることも、実行時に動的にロードすることもできます。
リンクされるのは、実行可能なオブジェクトモジュールです。一方、動的にロードできるモジュールには、COBOL 中間コードファイル (.int ファイル)、COBOL 生成コードファイル (.gnt ファイル)、および COBOL から呼び出し可能な共有オブジェクトがあります。
COBOL で開発された副プログラムを呼び出すには、次のどちらかの形式の CALL 文を呼び出し元の COBOL プログラムで使用します。
CALL "literal" USING ...
CALL data-name USING ...
literal と data-name には、COBOL 副プログラムの種類にかかわらず、PROGRAM-ID、入口点、および対応するソースファイルの基本名 (拡張子を含まないファイル名) のいずれかを表す文字列を指定します。COBOL 副プログラムの参照手段としてモジュールのパスとファイル名を指定することもできますが、特に理由がない限り、 Micro Focus では推奨していません。該当するモジュールが複数のファイルに存在したり、複数の形式で存在する場合や、アプリケーションを他の環境に移植した場合に、予期しない結果が生じる可能性があるためです。静的にリンクされたモジュールの呼び出しは literal に指定した文字列とともに、ネイティブコードジェネレータによって外部シンボルを参照するサブルーチンの呼び出しに変換されます。実行時の呼び出しは Server Express によって処理され、シンボルを定義して関連するファイルをロードするルーチンが自動生成されます。
注: リンク時に呼び出されるプログラムには、システムのアセンブラとリンカが認識できる名前を付けてください。使用できる文字は、数字、アルファベットの大文字と小文字、下線 (_)、およびハイフン (-) のみです。その他の文字を含んでいる入口点名は、システムのアセンブラやリンカで正しく認識されないため、修正する必要があります。
静的にリンクされたプログラムを直接呼び出すには、CALL リテラル 文を使用します。その結果、該当するプログラムが見つからないと、ランタイムシステムエラーが表示されます。ただし、ダイナミックローダが存在する場合には、該当するプログラムが動的にロードできるかがチェックされます。
動的にロード可能なプログラムを呼び出すには、CALL リテラル 文または CALL データ名 文を使用します。これらの文を実行すると、呼び出されたプログラムがダイナミックローダによって検索されます。
ダイナミックローダ自体をロードするには、Cob を使用します。詳細については、『Server Express ユーザガイド』の『COBOL システムインターフェイス (Cob)』の章を参照してください。
ダイナミックローダは、指定されたファイルを次の順序で検索します。
ダイナミックローダがディスク上でファイルを検索しなければならず、呼び出しでパス名が指定されていない場合は、その検索順序は、program_search_order ランタイム調整可能変数、および COBPATH 環境変数の設定により、決定されます。program_search_order ランタイム調整可能変数について詳しくは、『Server Express ユーザガイド』の『実行時の構成』の章を参照してください。また、COBPATH 環境変数については、『Server Express ユーザガイド』の付録、『環境変数』を参照してください。
呼び出しでディレクトリのパスを指定した場合には、そのディレクトリ内のファイルのみが検索されます。
拡張子を指定すると、その拡張子を持つファイルのみが検索対象になります。ただし、CALL 文で指定するファイル名には拡張子は付けないことをお奨めします。拡張子を含まないファイル名を指定すると、ダイナミックローダはファイルの基本名に拡張子、 .so を付け、一致する呼び出し可能な共有モジュールを検索します。その結果、該当する呼び出し可能な共有モジュールがディスク上に存在しない場合は、同様に拡張子、 .int を付けて中間コードファイルを検索し、見つからなければ拡張子、 .gnt を付けて .gnt ファイルを検索します。
ダイナミックローダは、一致する名前のプログラムが 1 つ見つかった時点で検索を終了します。
検索の結果、該当するプログラムが見つからなければ、ランタイムエラーが発生します。
動的にロードするファイル名の先頭文字がドル記号 ($) の場合には、ファイル名の最初の要素のマッピングがチェックされます。最初の要素とは、ファイル名の先頭からスラッシュ (/) の直前までの文字列のことです。詳細については、『ファイル操作』を参照してください。
たとえば、ソースプログラム内で次の CALL 文が検出された場合について考えてみましょう。
CALL "$MYLIB/A"
この場合、ファイル A は実行時に MYLIB 環境変数に設定されたディレクトリからロードされます。
COBOL 以外の言語で開発したサブプログラム (以下、「非 COBOL サブプログラム」と記す) にも、COBOL 標準の CALL...USING 文でアクセスできます。USING BY REFERENCE や USING BY CONTENT に指定したパラメータのアドレスが、非 COBOL サブプログラムに引数として渡されます (パラメータの宣言順序は、非 COBOL サブプログラムでも同じです)。そのため、非 COBOL サブプログラム側では、パラメータはすべてポインタとして宣言する必要があります。
CALL...USING 文を CALL...USING BY VALUE の形式で使用する場合でも、USING に指定したパラメータのデータ長が 4 バイトを超えると、そのパラメータは値ではなく参照で渡されます。ただし、参照で渡されたことを通知する警告は表示されません。また、CALL...USING BY VALUE 文に数字リテラルを指定すると、その値は 4 バイトの COMP-5 項目と同様に値で渡されます。つまり、その値はデータ項目を示すポインタとしてではなく、データ項目自体として処理されます。CALL...USING BY VALUE 文にデータ項目を指定する場合には、必ず COMP-5 項目を使用してください。
非 COBOL サブプログラムとの連絡では、呼び出しの規則を取り決めるべき場合もあります。詳細については、『COBOL のインターフェイス環境』の章を参照してください。
COBOL プログラムから C の関数を呼び出す方法の例を次に示します。
$set rtncode-size"4" working-storage section. 01 str. 03 str-text pic x(10). 03 filler pic x value x"00". * C の関数用に文字列の終端を NULL に設定 01 counter pic 9(8) comp-5 value zero. procedure division. call-c section. call "cfunc" using str, counter if return-code not = zero * RETURN-CODE は cfunc 関数内の return () で設定 display "ERROR" else display "OK" end-if stop run. ------------------------------------------------
cfunc (st, c) char *st; int *c; { ... return(0); }
この例のように、COBOL プログラム内で CALL 文を使用して非 COBOL モジュールを呼び出す場合には、COBOL の実行環境に影響を与えないように配慮すべきです。具体的には、次の点に注意します。
CANCEL 文は、参照先が非 COBOL プログラムの場合には無効です。
Server Express は予期しないシグナルを検出すると、次のランタイムシステムエラーを返します。
114 メモリ領域外の項目にアクセスしようとしている
115 予測しない信号を検出した
これらのエラーメッセージが、C と COBOL のモジュールをリンクしているときに返された場合には、C モジュールコードのエラーによってセグメンテーション違反などの状況が生じ、ハードウェア割り込みが行われた可能性があります。デバッガを使用して C のソースルーチンを慎重にチェックしてください。特に、COBOL プログラムとの間でやり取りするパラメータの形式とバイトオーダには注意を払ってください。
COBOL プログラム内には ENTRY 文を記述することが可能です。ENTRY は実行の開始する場所を示し、呼び出し側プログラムで手続き部のかわりに使用できます。
COBOL 自体は入口点を完全にサポートしていますが、ダイナミックローダによる問題が生じる可能性があります。ランタイムシステムは通常、呼び出されたプログラムを動的に検索します。言い換えれば、ロードされていないディスク上のプログラムは検索されないため、その中に記述された入口点も検出できません。たとえば、次の CALL 文を実行した場合について考えてみましょう。
call "abc" using ...
この文を検出すると、ランタイムシステムはロード済みのプログラムとライブラリ内を走査し、abc
に一致するプログラムまたは入口点を検索します。該当するプログラムが見つからなければ、さらに abc.ext
ファイルが検索されます
(.ext
は実行可能ファイルを示す拡張子の 1 つです。実行可能ファイルの種類については、『Server
Express ユーザガイド』の『アプリケーションのパッケージ化』の章にある『実行可能ファイルのタイプ
- 概要』を参照してください)。
ところが、ランタイムシステムはロードされていない実行可能ファイル内を走査しないため、abc
がそのようなプログラム内に記述されている入口点の場合には、エラーメッセージ (program not found) が生成されます。
そのため、入口点を正しく呼び出すには、該当する入口点を含むプログラムをランタイムシステムにロードしておく必要があります。
そのための手段の 1 つとして、入口点を含む各プログラムをライブラリファイル (.lbr ファイル) に格納する方法があります。.lbr ファイルの作成には、ライブラリ機能を使用します。.lbr ファイルを作成すると、すべての入口点が確実に呼び出されるようになります。
注: .lbr ファイルを呼び出しても、すべてのプログラムがランタイムシステムにロードされるわけではありません。.lbr ファイルの呼び出し時には、その中の各プログラムと入口点がランタイムシステムに登録されるのみだけです。その後、登録済みの項目が実際に呼び出されたときに、ランタイムシステムによって該当するプログラムがロードされます。
入口点を含むプログラムがロードされると、そのプログラム内のすべての入口点がランタイムシステムによって認識され、それ以降にロードされたプログラムから呼び出せるようになります。つまり、プログラムから他のプログラム内の入口点を呼び出すには、他のプログラムがすでにロードされており、内部の入口点がランタイムシステムに登録されている必要があります。
ここでは、呼び出された副プログラムからメインプログラムに、パラメータとしてコマンド行を渡す方法について説明します。メインプログラムとは、アプリケーション内で最初に実行されるプログラム、つまり、 COBOL システムから直接呼び出されるプログラムのことです。
コマンド行の最大長、形式、および内容はオペレーティングシステムによって異なります。他の環境に移植するアプリケーションは、この点に配慮して開発する必要があります。たとえば、コマンド行の最大長はシステムの上限値に設定するより、128 文字に設定する方が無難です。同様に移植性を考慮すると、コマンド行の文字列には英数字と等号 (=)、および空白文字のみを使用すべきです。
コマンド行を渡す手段は次のとおりです。
call progname using ...
call "progname" using ...
progname
には、最初の形式(引用符を含まない)では呼び出すプログラムの名前を格納したデータ項目、2 番めの形式(引用符を含む)では呼び出すプログラムの名前を指定します。
プログラム名は、呼び出し対象のプログラムまたは副プログラムを表す文字列です。ランタイムシステムでは、プログラム名は内部形式、つまり拡張子を付けない形式で扱われます。
そのため、実際にはサポートされている形式のいずれかの実行可能ファイルが呼び出されます。ランタイムシステムがサポートしている実行可能ファイルの形式は次のとおりです。
progname.lbr ファイルが見つかると、ランタイムシステムはそのファイルを開き、同じ基本名の実行可能ファイル (progname.gnt、progname.int、または progname) を検索してロードします。
CALL 文では、次のようにプログラム名を直接指定することも可能です。
call "progname.gnt" using ....
この形式で CALL 文を実行すると、ランタイムシステムは指定されたファイル名 (この例では progname.gnt) を持つプログラムのみを検索します。その結果、該当するプログラムが見つからなければ、エラーメッセージ (program not found) が生成されます。
起動後のランタイムシステムは、呼び出された副プログラムをすべてロードし、その管理を行います。ランタイムシステムは、呼び出されたプログラムを検索してロードするときに、一意のランタイムシステム識別子をプログラムに割り当てます (この識別子はランタイムシステム内で使用されます)。さらに、実メモリと仮想メモリの割り当てを行い、メモリの使用状況に応じてプログラムの一部をディスク上に移動します。
ランタイムシステムには、プログラムのパス名も記録されます。いったんプログラムがランタイムシステムにロードされると、物理的にキャンセルされない限り、同じプログラムが別にロードされることはありません。プログラムを物理的にキャンセルする方法については、『Server Express ユーザガイド』の『ランタイムスイッチの詳細』の章に記載されているランタイムスイッチ l の説明を参照してください。
ランタイムシステム上で動作している COBOL プログラムから副プログラムが呼び出されると、ランタイムシステムは次の一連の処理を実行します。
前述したように、ランタイムシステムは複数の実行可能ファイルを検索できます。これらのファイルが複数のディレクトリに格納されている場合も検索可能です。
注: 次に説明する検索順序は、実行可能ファイル (プログラム) のみが対象であり、データファイルや COBOL ソースファイルなど、その他の種類のファイルには適用されません。
アプリケーションが 1 つの実行可能ファイルのみで構成される場合には、検索順序に配慮する必要はありません。次の説明は、複数の実行可能ファイルから構成されるアプリケーションが対象です。
COBOL プログラムが、、次のように明示的に副プログラム名を呼び出した場合はつねに、ランタイムシステムは指定された拡張子を持つファイルのみを検索します。
call "myprog.gnt" using ...
この場合は、myprog.gnt
ファイルが検索されます。同じ基本名を持っているが、拡張子が異なる実行可能ファイルは検索されません。
COBOL プログラムが拡張子を指定せずに副プログラムを呼び出した場合は、ランタイムシステムは次に示す順序で副プログラムを検索します。
ここでは、次の呼び出しが実行された場合について説明します。
call "proga" using ...
ランタイムシステムは、基本名、 proga
を持つファイルを次の順序で検索します。
1 | proga.so | |
2 | proga.gnt | |
3 | proga.int | |
4 | proga.lbr | このファイルが見つかった場合は、ランタイムシステムはその内容を走査して実行可能ファイル名を検索します。 |
5 | proga | 拡張子を持たないファイル |
上記のファイルがいずれも見つからなかった場合、ランタイムシステムはエラーメッセージ、 program not found を生成します。
ランタイムシステムによるファイルの検索順序は、I1 ランタイムスイッチで変更できます。たとえば、基本名、 proga
を持つ実行可能ファイルは、このスイッチを指定すると、次の順序で検索されます。
1 | proga.so |
2 | proga.int |
3 | proga.gnt |
4 | proga.lbr |
このスイッチは、中間コード (.int ファイル) のみを生成するテスト段階では便利です。
副プログラムを見つけてロードするときに、ランタイムシステムはその副プログラムが見つかった場所 (ドライブ名とパス) を記録します。その副プログラムから、さらに別の副プログラムが呼び出されると、ランタイムシステムはカレントディレクトリを検索するかわりに、呼び出し元の副プログラムが見つかったディレクトリ内の検索を行います。
呼び出された副プログラムが、呼び出し元の副プログラムと同じディレクトリ内で見つからなかった場合、ランタイムシステムはあらためて標準の順序による副プログラムの検索を開始します。この仕組みは「継承」と呼ばれ、ランタイムシステムのデフォルト動作の 1 つです。
ランタイムシステムが複数のディレクトリ内で実行可能ファイルを検索するときに、各ディレクトリがどのような順序で検索されるかを把握しておくことも重要です。ディレクトリの検索順序は COBDIR 環境変数で指定されます。たとえば、プログラムで次の呼び出しが実行された場合について考えてみましょう。
call "myprog" using ...
ランタイムシステムは、まずアクティブディレクトリ内を検索し、myprog ファイルがロードされている (ロード後、キャンセルされていない) かをチェックします。
myprog がロードされていれば、ランタイムシステムは myprog に制御を渡します。ただし、次の条件に該当する場合には、myprog のデータ部 (DATA DIVISION) が再度読み込まれます。
キャンセルされている副プログラムが呼び出されると、ランタイムシステムはその副プログラムを検索してコード全体をロードします。
注: 副プログラムの呼び出しでは、継承がランタイムシステムの検索順序に与える影響を知っておく必要があります。呼び出した副プログラムと同じ名前のプログラムが複数のディレクトリ内に存在する場合は、意図したプログラムではないプログラムがロードされる可能性があります。
CALL プロトタイプは COBOL 言語の新しい機能の 1 つです。この機能を使用すると、各 CALL 文の正確性をコンパイル時にチェックできるようになり、複数のプログラムから構成されるアプリケーションに意図した機能を正しく実装するうえで役立ちます。CALL 文の構文については、『言語リファレンス』を参照してください。
COBOL プログラムが副プログラムを呼び出すときには、該当する CALL 文に指定されているパラメータのデータ型や数はチェックされません。CALL 文の USING 指定に指定されたパラメータのデータ型と、副プログラムの連絡節に記述されているパラメータのデータ型 (手続き部の USING 指定で参照される) が一致しないと、高い確率でアプリケーションエラーやランタイムシステムエラーが発生します。
プログラムと副プログラムの例で考えてみます。呼び出し側のプログラム (Mymain) のコードを示します。
program-id. MYMAIN. working-storage section. 01 . 05 myhandle pic x(4). 05 othervalue pic x(4) value "6x3b". procedure division. call 'MYROUTINE' using myhandle display "Othervalue is " othervalue.
次に副プログラム (Myroutine) のコードを示します。
program-id. MYROUTINE. linkage section. 01 myhandle usage pointer. procedure division using myhandle. set myhandle to null exit program.
このプログラムと副プログラムは、32 ビットシステム上では正常にコンパイルされて問題なく動作しますが、64 ビットシステム上では othervalue
の値が破損してしまいます。これは、ポインタの長さが前者では 4 バイトであるのに対し、後者では 8 バイトであるためです。
このような問題は、コンパイラが Mymain の処理中に Myroutine 側で定義されているパラメータのデータ型をチェックできれば、プログラムのコンパイル時点で見つけることが可能です。CALL プロトタイプを使用すると、呼び出される副プログラムの情報をコンパイラに渡し、プログラムと副プログラム間のパラメータの整合性をチェックさせることができます。
CALL プロトタイプは、呼び出される副プログラムのコードの簡略版またはモデルと見なされます。具体的には、次の情報が記述されています。
手続き部のコードは不要です。
作成したコードを CALL プロトタイプとして認識させるには、PROGRAM-ID 段落で IS EXTERNAL 句を指定します。
上記の Mymain に CALL プロトタイプを追加したコードを次に示します。
program-id. MYROUTINE is EXTERNAL. linkage section. 01 myhandle usage pointer. procedure division using myhandle. end program MYROUTINE. ******************************************************* * プロトタイプは通常、コピーファイル内で定義しますが、* * この例ではプログラムのコードに追加しています。 * ******************************************************* program-id. MYMAIN. working-storage section. 01 . 05 myhandle pic x(4). 05 othervalue pic x(4) value "6x3b". procedure division. call 'MYROUTINE' using myhandle display "Othervalue is " othervalue. end program MYMAIN.
このコードをコンパイルすると、パラメータの型が一致しないことを示す次の警告メッセージが表示されます。
14 call 'MYROUTINE' using myhandle *1059-E**************************************** ** Parameter is not consistent with that defined in prototype
このように CALL プロトタイプを活用すると、ランタイムテストを行わずにコーディングエラーを見つけることが可能になります。
理想的には、 COBOL プログラム内のすべての呼び出しに CALL プロトタイプを定義すべきですが、COBOL コードの量を考慮すると現実的ではありません。また、開発者は通常、プログラムの型チェックに慣れていません。プログラムのすべての呼び出しにプロトタイプを活用しても、厳しい型チェックを行うと、有効な呼び出しが無効と判断され、膨大なコンパイラエラーが生成されてしまうことが考えられます。Server Express では、このため、緩やかな型チェックを使用したり、USING で ANY キーワードを使用することができます。
『言語リファレンス - 追加トピック』の『例』の章にある『CALL プロトタイプ』には、CALL プロトタイプの詳しい例が掲載されています。
ANY は、 USING 指定でパラメータのかわりに指定できるキーワードです。ANY キーワードを使用すると、プロトタイプ定義したルーチンを呼び出す CALL 文の該当位置のパラメータが、呼び出されるプログラム側の対応するパラメータと同じデータ型 (およびサイズ) として扱われるようになります。たとえば、次のプロトタイプを使用すると、前述の警告メッセージは回避されます。
program-id. MYROUTINE is EXTERNAL. procedure division using any. end program MYROUTINE.
ANY キーワードの詳細については、『言語リファレンス』を参照してください。
Server Express は、デフォルトで BY VALUE で指定されたバイナリデータ項目に対して、緩やかな型チェックを実行します。そのため、呼び出し側プログラムで定義した 2 進データ項目と、呼び出されるプログラム側の対応する 2 進データ項目のサイズが一致しない場合でも、プログラムは正常にコンパイルされます。たとえば、CALL 文の USING 指定で PIC X(2) COMP 型のデータ項目を指定している場合には、CALL プロトタイプ内の対応するデータ項目が PIC X(n) COMP 型であればエラーは発生しません (n の有効範囲は、32 ビットシステムでは 1 〜 4、64 ビットシステムでは 1 〜 8 です)。
緩やかな型チェックが実行されるコードの例を次に示します。
program-id. MYROUTINE is EXTERNAL. linkage section. 01 callee-value pic x(2) comp-5. procedure division using by value callee-value. end program MYROUTINE. program-id. MYMAIN. working-storage section. 01 . 05 caller-value pic x(4) value 123. procedure division. call 'MYROUTINE' using by value caller-value end program MYMAIN.
この例で caller-value
に割り当てた値が大きく、PIC X(2) COMP-5 データ項目に収まらない場合には、バイナリデータが切り捨てられます。プログラムのロジックによっては、このような切り捨て処理によって問題が生じる可能性があるため、これを避けるために、PROTOTYPE"STRICT"
コンパイラ指令を使用して、型チェックをより厳格に設定する場合もあります。上記のプログラムを PROTOTYPE"STRICT"
を指定してコンパイルすると、データ型の不一致を示す警告メッセージが生成されます。PROTOTYPE 指令の詳細については、『Server
Express ユーザガイド』の『コンパイラへの指令』の章を参照してください。
COBOL では、呼び出し側プログラム、呼び出されるプログラム、および CALL プロトタイプの USING で指定するパラメータのデータ型を統一する手段として、TYPEDEF を効果的に利用できます。TYPEDEF の詳細については、『言語リファレンス』を参照してください。
『CALL プロトタイプ』で説明したように、CALL プロトタイプを使用すると、対応するデータ項目の型が一致していない場合にエラーが発生します。このエラーを回避し、CALL 文と USING のパラメータを正しく記述するには、CALL プロトタイプ内の USING パラメータのデータ定義が、このプロトタイプを呼び出すプログラムに正しくコピーされている必要があります。ただし、この作業を手動で行うと、保守効率の面で問題が発生し、プログラムの作成中に整合性が失われる可能性があります。
データ定義のコピーを簡単に行うには、 CALL プロトタイプ内で TYPEDEF を使用して、正しいパラメータを記述することができます。次に例を示します。
program-id. MYROUTINE is EXTERNAL. linkage section. 01 callee-value-t pic x(2) comp-5 is typedef. 01 callee-value usage callee-value-t. procedure division using callee-value. end program MYROUTINE. program-id. MYMAIN. working-storage section. 01 . 05 caller-value usage callee-value-t. procedure division. call 'MYROUTINE' using caller-value end program MYMAIN.
次の例に示すように、TYPEDEF では単純なデータ記述のみでなく、レコード構造全体を定義することもできます。
program-id. MYROUTINE is EXTERNAL. linkage section. 01 callee-value-t is typedef. 05 callee-value-item-1 pic x(2) comp-5. 05 callee-value-item-2 pic x(4). 01 callee-value usage callee-value-t. procedure division using callee-value. end program MYROUTINE. program-id. MYMAIN. working-storage section. 01 . 05 caller-value usage callee-value-t. procedure division. move 123 to callee-value-item-1 of caller-value move 'abcdef' to callee-value-item-2 of caller-value call 'MYROUTINE' using caller-value end program MYMAIN.
CALL プロトタイプ内で TYPEDEF 定義したデータ型は、そのプロトタイプを使用するすべてのプログラムでも使用可能です。
Server Express 2.0 では、COBOL システムライブラリルーチン用のプロトタイプが追加されており、プログラム内で定義したデータ項目とライブラリルーチン内の該当項目のデータ型を確実に一致させることが可能です。このプロトタイプは、32 ビットアプリケーションを 64 ビット版に移行する場合や、データ型の一致が不可欠な処理などに特に有効です。
ライブラリルーチン用のプロトタイプの詳細については、『ライブラリルーチン』を参照してください。.
Copyright © 2002 Micro Focus International Limited. All rights reserved.
本書、ならびに使用されている固有の商標および商品名は国際著作権法で保護されています。
![]() | パフォーマンスの最適化 | 拡張言語機能 | ![]() |