【COBOL】EXTERNAL句完全ガイド|プログラム間データ共有の仕組み・FD EXTERNAL・USING/GLOBALとの使い分け・実践パターン

【COBOL】EXTERNAL句で外部ファイルのデータ項目を定義する方法 COBOL

COBOLのプログラム連携というと、CALL文とUSING句による引数渡しが真っ先に浮かびます。しかし「引数に乗せたくないが複数プログラムで使いたい共有領域」が必要になる場面があります。そのときに使うのが IS EXTERNAL 句 です。

EXTERNAL句を使うと、同じラン単位(run unit)内のすべてのプログラムが、引数を渡すことなく同一のデータ領域を参照・更新できます。ファイルコネクタにも適用でき、複数プログラムが同じファイルを開いた状態で扱うことも可能です。本記事ではEXTERNAL句の仕組みを丁寧に解説し、USING句・GLOBAL句との使い分けや実践パターンまで詳しく説明します。

スポンサーリンク

EXTERNAL句とは

EXTERNAL句(正式には IS EXTERNAL)は、COBOLのデータ定義に付加する句で、そのデータ項目をラン単位外部データ(run-unit external data)として宣言します

「ラン単位外部データ」とは、特定のプログラムに属さず、ラン単位全体で1か所だけ存在するデータ領域のことです。同一ラン単位に属するプログラムが同名・同定義のEXTERNAL項目を宣言すれば、すべてが同一メモリを指します。

ラン単位(run unit)とは
メインプログラムから始まり、CALLで呼ばれるすべてのサブプログラムを含む、1回の実行フローの全体を指します。STOP RUNで終了します。

EXTERNAL句が使える場所

適用場所 記述対象 効果
WORKING-STORAGE SECTION 01レベルの集団項目または基本項目 プログラム間共有データ領域
FILE SECTION(FDエントリ) FD(ファイル記述エントリ) プログラム間共有ファイルコネクタ
EXTERNAL句は LINKAGE SECTIONLOCAL-STORAGE SECTION には使えません。また、WORKING-STORAGEでは 01レベルのみに指定できます(下位レベルへの直接指定は不可)。

WORKING-STORAGE EXTERNAL の基本構文

WORKING-STORAGEにおけるEXTERNAL句の書き方は次のとおりです。

基本構文
DATA DIVISION.
WORKING-STORAGE SECTION.
01  共有データ名  IS EXTERNAL.
    05  項目1     PIC X(10).
    05  項目2     PIC 9(5).
    05  項目3     PIC 9(3)V99.

別のプログラムで同じデータ領域を参照するには、まったく同じデータ名・まったく同じ定義でEXTERNAL句を再宣言します。

別プログラムでの参照(同一定義が必須)
*> プログラムBでの宣言(プログラムAと同一定義が必要)
DATA DIVISION.
WORKING-STORAGE SECTION.
01  共有データ名  IS EXTERNAL.
    05  項目1     PIC X(10).
    05  項目2     PIC 9(5).
    05  項目3     PIC 9(3)V99.
同一定義のルール
EXTERNALを使う全プログラムで、データ名・レベル番号・PIC句・USAGE句が一致している必要があります。定義が異なると、コンパイラや実行時に不定動作を引き起こす可能性があります。COPY句で共通定義を管理するのが実務の基本です。

FD EXTERNAL の基本構文

ファイル記述エントリ(FD)にEXTERNAL句を指定すると、ファイルコネクタ自体が共有されます。一方のプログラムがファイルをOPENすれば、別のプログラムもそのファイルコネクタを通じて読み書きできます。

FD EXTERNAL の構文
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT 共有ファイル   ASSIGN TO "SHARED.DAT"
                         ORGANIZATION IS SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD  共有ファイル  IS EXTERNAL.
01  共有レコード.
    05  レコードID    PIC 9(8).
    05  データ内容    PIC X(50).
    05  更新フラグ    PIC X(1).

別プログラムでも同様に宣言します。FILECONTROLのSELECT文も同じASSIGN先でなければなりません。

FD EXTERNALを使う場合、SELECTのASSIGN句が両プログラムで一致している必要があります。また、ファイルのOPEN/CLOSEはどのプログラムからでも行えますが、二重OPENはエラーになります。

EXTERNAL・USING・GLOBALの使い分け

COBOLにはプログラム間でデータを共有する手段が複数あります。それぞれの特性を理解して使い分けることが重要です。

方式 スコープ 対象 宣言方法 主な用途
EXTERNAL ラン単位全体 別コンパイル単位間 引数なし・定義一致必須 設定テーブル・共有カウンタ
USING(BY REFERENCE) CALL先のみ 直接の呼び元・呼び先間 CALL毎に明示指定 計算引数・処理結果の受け渡し
GLOBAL 宣言プログラムと内包プログラム ネスト(内包)されたプログラム間 上位プログラムで宣言するだけ 上位管理変数・フラグの共有
使い分けの指針
USING:1回のCALL呼び出しで渡す一時的なデータ(計算値・処理結果など)
GLOBAL:ネスト構造内の上位フラグや管理変数(別コンパイル不可)
EXTERNAL:ラン単位を通じて生き続ける共有設定・累積カウンタ・共有ファイルコネクタ

実践パターン

パターン1:共通設定テーブルの共有

複数のサブプログラムが参照する設定値(処理日付・環境区分・パラメータ)を、メインプログラムで一度ロードし、EXTERNALで全プログラムに公開する定番パターンです。

共通定義コピー句(EXTSHARE.CPY)
*> EXTSHARE.CPY - すべてのプログラムでCOPYして使う
01  共通設定領域   IS EXTERNAL.
    05  処理日付       PIC 9(8).        *> YYYYMMDD
    05  環境区分       PIC X(1).        *> P:本番 T:テスト
    05  処理件数       PIC 9(9) COMP.   *> 累積件数カウンタ
    05  エラーコード   PIC X(4).        *> 最終エラーコード
    05  FILLER         PIC X(10).
メインプログラム(初期化)
IDENTIFICATION DIVISION.
PROGRAM-ID. MAIN-PGM.

DATA DIVISION.
WORKING-STORAGE SECTION.
    COPY EXTSHARE.

PROCEDURE DIVISION.
    *> 起動時に設定値をロード
    MOVE FUNCTION CURRENT-DATE(1:8)
        TO 処理日付
    MOVE 'P'           TO 環境区分
    MOVE ZEROS         TO 処理件数
    MOVE SPACES        TO エラーコード

    CALL 'SUB-PGM-A'
    CALL 'SUB-PGM-B'
    DISPLAY '総処理件数: ' 処理件数
    STOP RUN.
サブプログラムA(設定値を参照・更新)
IDENTIFICATION DIVISION.
PROGRAM-ID. SUB-PGM-A.

DATA DIVISION.
WORKING-STORAGE SECTION.
    COPY EXTSHARE.    *> 同一定義を宣言するだけで共有される

PROCEDURE DIVISION.
    *> 処理日付・環境区分を引数なしで参照できる
    IF 環境区分 = 'P'
        DISPLAY '本番処理: ' 処理日付
    END-IF
    ADD 1 TO 処理件数    *> カウンタを更新(メインに即時反映)
    GOBACK.

パターン2:FD EXTERNALによる共有ファイルコネクタ

メインプログラムでファイルをOPENし、サブプログラムでREAD/WRITEするパターンです。ファイルのOPEN/CLOSEを分散させず、OPENはメインのみ、読み書きはサブという役割分担が実現できます。

メインプログラム(OPENとCLOSEを担当)
IDENTIFICATION DIVISION.
PROGRAM-ID. MAIN-PGM.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT 入力ファイル  ASSIGN TO "INPUT.DAT"
                        ORGANIZATION IS SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD  入力ファイル  IS EXTERNAL.
01  入力レコード.
    05  顧客コード    PIC X(8).
    05  顧客名        PIC X(20).
    05  金額          PIC 9(7).

PROCEDURE DIVISION.
    OPEN INPUT 入力ファイル
    CALL 'READ-PGM'    *> READはサブプログラムに委譲
    CLOSE 入力ファイル
    STOP RUN.
サブプログラム(READを担当)
IDENTIFICATION DIVISION.
PROGRAM-ID. READ-PGM.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT 入力ファイル  ASSIGN TO "INPUT.DAT"   *> 同一ASSIGN
                        ORGANIZATION IS SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD  入力ファイル  IS EXTERNAL.
01  入力レコード.
    05  顧客コード    PIC X(8).
    05  顧客名        PIC X(20).
    05  金額          PIC 9(7).

WORKING-STORAGE SECTION.
01  WS-EOF-FLAG    PIC X(1) VALUE 'N'.

PROCEDURE DIVISION.
    PERFORM UNTIL WS-EOF-FLAG = 'Y'
        READ 入力ファイル
            AT END
                MOVE 'Y' TO WS-EOF-FLAG
            NOT AT END
                DISPLAY 顧客コード ' ' 顧客名 ' ' 金額
        END-READ
    END-PERFORM
    GOBACK.

パターン3:エラー情報の共有(集中エラー管理)

どのサブプログラムで発生したエラーも、共通のEXTERNAL領域に書き込むパターンです。メインプログラムは処理後に一括してエラー内容を確認できます。

エラー共有領域の定義(EXTERR.CPY)
*> EXTERR.CPY
01  エラー共有領域   IS EXTERNAL.
    05  エラー発生数    PIC 9(4) COMP.
    05  エラー詳細      OCCURS 10 TIMES.
        10  エラープログラム名    PIC X(8).
        10  エラーコード          PIC X(4).
        10  エラーメッセージ      PIC X(40).
サブプログラムでのエラー書き込み
IDENTIFICATION DIVISION.
PROGRAM-ID. PROC-PGM.

DATA DIVISION.
WORKING-STORAGE SECTION.
    COPY EXTERR.
01  WS-ERR-IDX   PIC 9(4) COMP.

PROCEDURE DIVISION.
    *> エラー発生時:共有領域に記録
    ADD 1 TO エラー発生数
    MOVE エラー発生数 TO WS-ERR-IDX
    MOVE 'PROC-PGM' TO エラープログラム名(WS-ERR-IDX)
    MOVE '0001'     TO エラーコード(WS-ERR-IDX)
    MOVE '金額が負値です' TO エラーメッセージ(WS-ERR-IDX)
    GOBACK.

落とし穴と注意点

定義不一致による未定義動作

最も危険な落とし穴です。プログラムAとプログラムBで同名のEXTERNAL項目を宣言しても、PIC句やUSAGE句が少しでも異なると、同一メモリを別の構造で読み書きすることになります。コンパイルエラーにならずに実行され、データ破損やアベンドが後から気づきにくい形で発生します。必ずCOPY句で単一の定義を全プログラムに共有してください。

EXTERNAL領域の初期化タイミング

EXTERNAL領域はラン単位の開始時に一度だけ確保され、プログラムが複数回CALLされても初期化されません。WORKING-STORAGEの通常項目はCALLのたびにVALUE句で再初期化されますが、EXTERNAL項目はその対象外です。カウンタや累積値を使う場合は、初期化するタイミングを設計で明確にしておく必要があります。

FD EXTERNALの二重OPEN問題

FD EXTERNALを使う場合、ファイルコネクタは共有されていますが、OPENは一度だけしか行えません。メインプログラムでOPENした後にサブプログラムが再度OPENしようとすると実行時エラーになります。「誰がOPEN/CLOSEを担当するか」を設計段階で明確に決め、コメントで明記しておきましょう。

ネスト(内包)プログラムにはGLOBALを使う

CONTAIN句でネストされた内包プログラム(Contained program)の場合、EXTERNAL句は使用できません。コンパイラによってはエラーになります。内包プログラムには IS GLOBAL 句を使い、上位プログラムのデータを参照してください。EXTERNALは別コンパイル単位のプログラム間専用です。

マルチスレッド環境での競合

一部のCOBOL処理系でマルチスレッドを使用する場合、EXTERNAL領域は複数スレッドから同時アクセスされる可能性があります。排他制御(MUTEX相当)を別途実装しないとデータ破損が起きます。シングルスレッド・バッチ処理の文脈で使うのが最も安全です。

よくある質問

QEXTERNAL句はすべてのCOBOLコンパイラで使えますか?
ACOBOL 85以降の標準で規定されているため、主要なコンパイラ(IBM Enterprise COBOL・GnuCOBOL・Micro Focus等)では対応しています。ただし、古い環境やCOBOL 74以前の方言ではサポートされていない場合があります。事前にコンパイラのマニュアルで確認してください。
QCOPY句でEXTERNALの定義を共有する際、REPLACING句は使えますか?
A使えますが注意が必要です。REPLACING句でデータ名を変更すると、プログラム間で「別名・同定義」になります。コンパイラが名前でEXTERNAL領域を特定する場合(多くの実装)は別領域として扱われ、共有されません。定義の共有にCOPYを使う場合はREPLACING句でデータ名を変えないのが原則です。
QEXTERNALとLINKAGE SECTIONはどう使い分けますか?
ALINKAGE SECTIONはCALL時にUSINGで渡されたデータへのポインタを受け取る領域で、呼び出しごとに異なるデータを渡せます。EXTERNALはラン単位全体で1つの固定領域を共有します。「呼び出しごとに異なるデータ」はLINKAGE、「ラン単位を通じて一つの共有領域」はEXTERNALという使い分けが基本です。
QサブプログラムがCANCELされてもEXTERNAL領域は保持されますか?
ACANCEL文はプログラムの実行可能プログラムライブラリをアンロードし、次回CALL時に初期状態から再実行させます。ただしEXTERNAL領域はプログラムに属さずラン単位に属するため、CANCEL後も領域の内容は保持されます。CANCELしたプログラムのWORKING-STORAGE(通常項目)はリセットされますが、EXTERNAL項目はリセットされません。
QEXTERNAL句を指定した01項目のVALUE句は有効ですか?
ACOBOL標準ではEXTERNAL項目のVALUE句は許可されていますが、初期値が適用されるのは「最初に領域が確保されたとき(ラン単位開始時)」のみです。複数のプログラムがVALUE句で異なる初期値を指定した場合の動作はコンパイラ依存です。安全を期すなら、初期化処理を明示的にPROCEDURE DIVISIONで行うプログラムを1つ決めておきましょう。

まとめ

EXTERNAL句の要点を整理します。

項目 内容
適用場所 WORKING-STORAGE SECTION の01項目 / FILE SECTION のFDエントリ
効果 同一ラン単位内の全プログラムが同名・同定義で宣言すれば同一領域を共有
定義ルール データ名・レベル・PIC・USAGEが完全一致必須。COPY句での一元管理が原則
初期化 ラン単位開始時に一度だけ確保。CALLのたびの再初期化はされない
FD EXTERNAL ファイルコネクタを共有。OPENは一方のプログラムのみ、READは別プログラムという分担が可能
USING比較 USINGはCALL単位・一時的な引数渡し。EXTERNALはラン単位を通じた永続的な共有領域
GLOBAL比較 GLOBALはネスト(内包)プログラム向け。EXTERNALは別コンパイル単位向け
主な用途 共通設定テーブル・累積カウンタ・集中エラー管理・共有ファイルコネクタ
注意点 定義不一致は実行時の無音のデータ破損につながる。マルチスレッド環境では競合に要注意

EXTERNAL句は使いどころを絞れば強力なプログラム間連携手段です。ただし「見えない共有」はバグの温床にもなります。COPY句による定義の一元管理と、初期化タイミングの設計を徹底することで、保守性の高いマルチモジュールCOBOLシステムを構築できます。

引数渡しの仕組みについては引数の使い方完全ガイド(BY REFERENCE・BY CONTENT・LINKAGE SECTION)を、サブルーチン呼び出し全般についてはCALL文完全ガイドも合わせてご覧ください。