COBOLのREDEFINES句は、同じメモリ領域に対して複数の論理的な見え方を定義する機能です。日付の年月日分解、固定長ファイルの複数レイアウト処理、バイナリデータの解釈変換など、実務で頻繁に登場する場面で威力を発揮します。
この記事では、REDEFINES句の仕組みと構文規則を基礎から解説し、業務開発で実際に使われるパターンを体系的にまとめます。
REDEFINES句とは
REDEFINES句は、すでに定義されたデータ項目と同じメモリ領域を、別の名前・別のデータ構造で参照するための機能です。2つの項目は同じ物理アドレスを共有しており、一方を変更するともう一方にも即座に反映されます。
イメージとしては「同じ引き出しに2枚のラベルを貼る」ようなものです。引き出しの中身は1つですが、ラベルに書かれた解釈が異なります。
| 観点 | 定義 | 説明 |
|---|---|---|
| 元の定義 | WS-DATE PIC 9(8) | 20260101 という8桁数値として扱う |
| 再定義 | WS-DATE-PARTS REDEFINES WS-DATE | 年4桁・月2桁・日2桁の3フィールドとして扱う |
| 共通点 | 同じメモリ領域 | 値の変更は両方に反映される |
REDEFINES句を使う主な目的は次の3つです。
- 同じ領域を異なる構造で解釈したい(日付の分解、レコードタイプ別処理)
- 型変換なしでビット・バイト構造にアクセスしたい(バイナリ処理)
- 固定長ファイルの複数レコードレイアウトを定義したい(ファイル処理)
基本構文
レベル番号 再定義名 REDEFINES 元の項目名.
(従属項目の定義...)
WORKING-STORAGE SECTION.
01 WS-DATE-FULL PIC 9(8).
01 WS-DATE-PARTS REDEFINES WS-DATE-FULL.
05 WS-YEAR PIC 9(4).
05 WS-MONTH PIC 9(2).
05 WS-DAY PIC 9(2).
この例では、WS-DATE-FULL(8桁数値)とWS-DATE-PARTS(年月日の3フィールド)が同じ8バイトを共有しています。WS-DATE-FULL に 20260101 を代入すると、WS-YEAR は 2026、WS-MONTH は 01、WS-DAY は 01 として読み取れます。
構文規則と制約
REDEFINES句には守らなければならないルールがあります。コンパイルエラーにつながる制約を中心に整理します。
ルール一覧
| ルール | 内容 |
|---|---|
| 同一レベル・同一親 | 再定義する項目と元の項目は、同じレベル番号・同じ親グループ項目でなければならない |
| 直後に記述 | 再定義項目は、元の項目のすぐ後(または別のREDEFINES項目の直後)に書く |
| VALUE句の使用禁止 | REDEFINES句を持つ項目(および従属項目)にはVALUE句を使えない(88レベルの条件名は例外) |
| サイズの一致 | 01レベル以外では、再定義後のサイズは元の項目と完全に一致させる(01レベルは元以下のサイズも可) |
| OCCURS句の再定義不可 | OCCURS句を持つ項目をREDEFINESの対象にすることはできない(逆は可) |
VALUE句はREDEFINES項目に使えない
REDEFINES句を持つ項目にVALUE句を書くとコンパイルエラーになります。初期値が必要な場合は元の項目(再定義される側)にVALUE句を設定するか、PROCEDURE DIVISIONで初期化してください。
01 WS-ORIGINAL PIC X(4) VALUE 'ABCD'. * NG: REDEFINES項目にVALUE句は使えない 01 WS-REDEF REDEFINES WS-ORIGINAL PIC 9(4) VALUE 1234.
* OKパターン1: 元の項目にVALUEを設定する 01 WS-DATA PIC X(4) VALUE '0100'. 01 WS-NUM REDEFINES WS-DATA PIC 9(4). * OKパターン2: PROCEDURE DIVISIONで代入する MOVE '0100' TO WS-DATA
複数のREDEFINESを同一項目に適用する
1つの項目に対して複数のREDEFINES定義を並べることができます。固定長ファイルのレコードタイプが複数ある場合や、同じ領域を複数の構造で解釈したい場合に使います。
WORKING-STORAGE SECTION.
* 基底項目: 100バイトの共通領域
01 WS-RECORD PIC X(100).
* レイアウトA: 売上明細レコード
01 WS-SALES-REC REDEFINES WS-RECORD.
05 WS-REC-TYPE PIC X(1). *> レコード種別 '1'
05 WS-SHOP-CODE PIC 9(4). *> 店舗コード
05 WS-ITEM-CODE PIC X(10). *> 商品コード
05 WS-AMOUNT PIC 9(9)V99. *> 金額
05 FILLER PIC X(74).
* レイアウトB: 在庫調整レコード
01 WS-STOCK-REC REDEFINES WS-RECORD.
05 WS-REC-TYPE2 PIC X(1). *> レコード種別 '2'
05 WS-WH-CODE PIC 9(3). *> 倉庫コード
05 WS-ITEM-CODE2 PIC X(10). *> 商品コード
05 WS-QTY PIC 9(7). *> 数量
05 FILLER PIC X(78).
* レイアウトC: ヘッダレコード
01 WS-HEADER-REC REDEFINES WS-RECORD.
05 WS-REC-TYPE3 PIC X(1). *> レコード種別 '0'
05 WS-DATE-H PIC 9(8). *> 処理日付
05 WS-BATCH-NO PIC 9(6). *> バッチ番号
05 FILLER PIC X(85).
PROCEDURE DIVISION.
READ INPUT-FILE
AT END MOVE 'Y' TO WS-EOF-FLAG
END-READ
EVALUATE WS-REC-TYPE
WHEN '0'
PERFORM PROCESS-HEADER
WHEN '1'
PERFORM PROCESS-SALES
WHEN '2'
PERFORM PROCESS-STOCK
WHEN OTHER
PERFORM PROCESS-UNKNOWN
END-EVALUATE.
PROCESS-SALES.
*> WS-SALES-RECのフィールドで処理
DISPLAY '店舗: ' WS-SHOP-CODE ' 金額: ' WS-AMOUNT.
複数REDEFINESのポイント: 再定義する側の項目(WS-SALES-REC, WS-STOCK-REC, WS-HEADER-REC)はすべて同じ元の項目(WS-RECORD)をREDEFINESします。再定義した項目をさらにREDEFINESするチェーン構造は規格では非推奨です。
主要な使用パターン
日付の年月日分解
CURRENT-DATEで取得した日付(YYYYMMDD形式の8桁)をREDEFINESで分解するのは、COBOL業務プログラムで最も多く見られるパターンのひとつです。
WORKING-STORAGE SECTION.
01 WS-CURRENT-DATE-WORK.
05 WS-CURRENT-DATE PIC X(21).
05 FILLER REDEFINES WS-CURRENT-DATE.
10 WS-YEAR PIC 9(4).
10 WS-MONTH PIC 9(2).
10 WS-DAY PIC 9(2).
10 FILLER PIC X(13).
PROCEDURE DIVISION.
MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-DATE
DISPLAY '西暦: ' WS-YEAR
DISPLAY '月 : ' WS-MONTH
DISPLAY '日 : ' WS-DAY.
文字列と数値の二重解釈
外部から文字列として受け取ったデータを、数値として算術演算したい場合に使います。MOVE文で変換するより、REDEFINESで別名を付けるほうが明確です。
WORKING-STORAGE SECTION.
* ACCEPT や外部入力で文字列として受け取る領域
01 WS-PRICE-CHAR PIC X(8).
* 同じ8バイトを符号なし整数として解釈
01 WS-PRICE-NUM REDEFINES WS-PRICE-CHAR PIC 9(8).
* 計算結果用(別領域)
01 WS-TAX PIC 9(8)V99.
01 WS-TOTAL PIC 9(9)V99.
PROCEDURE DIVISION.
MOVE '00012800' TO WS-PRICE-CHAR *> 文字列として代入
*> WS-PRICE-NUM で数値として演算できる
COMPUTE WS-TAX = WS-PRICE-NUM * 0.10
COMPUTE WS-TOTAL = WS-PRICE-NUM + WS-TAX
DISPLAY '税込金額: ' WS-TOTAL.
バイナリデータのバイト操作
COMP(2バイト/4バイト)などのバイナリ項目を個別のバイトとしてアクセスしたいときに使います。低レベルなデータ操作や通信プロトコルの実装で使われるパターンです。
WORKING-STORAGE SECTION.
* 2バイト符号なし整数(COMP-5 = バイナリ)
01 WS-WORD PIC 9(4) COMP-5.
* 同じ2バイトを上位・下位バイトとして解釈
01 WS-BYTES REDEFINES WS-WORD.
05 WS-HIGH-BYTE PIC X(1).
05 WS-LOW-BYTE PIC X(1).
PROCEDURE DIVISION.
MOVE 256 TO WS-WORD *> 0x0100
DISPLAY '上位バイト: ' WS-HIGH-BYTE
DISPLAY '下位バイト: ' WS-LOW-BYTE.
区分コードによるユニオン型定義
C言語の union に相当する使い方です。先頭の区分コードで「どのレイアウトとして解釈するか」を決定します。
WORKING-STORAGE SECTION.
01 WS-EMP-COMMON.
05 WS-EMP-TYPE PIC X(1). *> '1'=正社員 '2'=派遣
05 WS-EMP-DATA PIC X(50).
01 WS-REGULAR REDEFINES WS-EMP-COMMON.
05 FILLER PIC X(1).
05 WS-DEPT-CODE PIC 9(4). *> 部署コード(正社員のみ)
05 WS-GRADE PIC 9(2). *> グレード(正社員のみ)
05 FILLER PIC X(44).
01 WS-CONTRACT REDEFINES WS-EMP-COMMON.
05 FILLER PIC X(1).
05 WS-AGENCY-CD PIC X(6). *> 派遣会社コード
05 WS-END-DATE PIC 9(8). *> 契約終了日
05 FILLER PIC X(36).
PROCEDURE DIVISION.
IF WS-EMP-TYPE = '1'
DISPLAY '部署: ' WS-DEPT-CODE
ELSE
DISPLAY '派遣会社: ' WS-AGENCY-CD
END-IF.
FDでのREDEFINES(ファイル処理の複数レコード定義)
COBOL業務でよく使われるのが、FD(ファイル記述子)内での複数レコード定義です。同一ファイルに複数のレコードタイプが混在する場合、FDに直接複数の01レベルを並べるとREDEFINES相当の動作をします(これはFD特有の暗黙REDEFINESです)。
FILE SECTION.
FD TRANSACTION-FILE.
* FD直下の複数01レベルは自動的に同一領域を共有(暗黙REDEFINES)
01 TRN-COMMON-RECORD PIC X(100).
01 TRN-SALES-RECORD.
05 TRN-TYPE PIC X(1).
05 TRN-SHOP PIC 9(4).
05 TRN-AMOUNT PIC 9(9)V99.
05 FILLER PIC X(85).
01 TRN-CANCEL-RECORD.
05 TRN-TYPE2 PIC X(1).
05 TRN-ORG-DATE PIC 9(8).
05 TRN-ORG-SEQ PIC 9(6).
05 FILLER PIC X(84).
PROCEDURE DIVISION.
READ TRANSACTION-FILE INTO WS-WORK-AREA
AT END MOVE 'Y' TO WS-EOF-FLAG
END-READ
*> TRN-COMMON-RECORD で先頭1バイト(レコード種別)を確認
EVALUATE TRN-TYPE
WHEN '1'
*> TRN-SALES-RECORD のフィールドで処理
ADD TRN-AMOUNT TO WS-TOTAL-AMOUNT
WHEN '9'
*> TRN-CANCEL-RECORD のフィールドで処理
PERFORM CANCEL-PROCESS
END-EVALUATE.
FDの暗黙REDEFINESとWORKING-STORAGEのREDEFINESの違い
FD直下の複数01レベルは自動的に同じレコードバッファを共有します(明示的なREDEFINES句は不要)。WORKING-STORAGEでは明示的にREDEFINES句を書く必要があります。
OCCURS句との組み合わせ
REDEFINESの対象項目にOCCURS句を使うことはできませんが、REDEFINESする側の項目にOCCURS句を使うことは可能です。これにより、連続したバイト列を配列として解釈するパターンが実現できます。
WORKING-STORAGE SECTION.
* 12バイトの固定領域(4桁×3か月分)
01 WS-QUARTERLY-DATA PIC 9(12).
* 同じ12バイトを3要素の配列として解釈
01 WS-MONTHLY-ARRAY REDEFINES WS-QUARTERLY-DATA.
05 WS-MONTH-AMT PIC 9(4) OCCURS 3 TIMES.
PROCEDURE DIVISION.
MOVE 012303450678 TO WS-QUARTERLY-DATA
PERFORM VARYING WS-IDX FROM 1 BY 1 UNTIL WS-IDX > 3
DISPLAY '月' WS-IDX '売上: ' WS-MONTH-AMT(WS-IDX)
END-PERFORM.
OCCURS句を持つ項目はREDEFINESできない
以下はコンパイルエラーです。REDEFINES句はOCCURS句を持つ項目を参照できません。
01 WS-ARRAY.
05 WS-ITEM OCCURS 3 TIMES PIC 9(4).
* NG: OCCURS句を持つ項目をREDEFINESの対象にできない
01 WS-WHOLE REDEFINES WS-ITEM PIC 9(12).
正しくは、配列を包む親グループ項目(OCCURS句を持たない)をREDEFINESします。
* OK: 親グループ(WS-ARRAY)をREDEFINESする
01 WS-ARRAY.
05 WS-ITEM OCCURS 3 TIMES PIC 9(4).
01 WS-WHOLE REDEFINES WS-ARRAY PIC 9(12).
88レベルとの組み合わせ
REDEFINES項目のフィールドに88レベルの条件名を定義することができます。ただし、88レベル自体はVALUE句を使えるため、「REDEFINES項目にはVALUE句禁止」のルールの例外になります。
WORKING-STORAGE SECTION.
01 WS-MESSAGE-RAW PIC X(10).
01 WS-MESSAGE-PARSED REDEFINES WS-MESSAGE-RAW.
05 WS-MSG-TYPE PIC X(2).
05 WS-MSG-BODY PIC X(8).
* 88レベルはREDEFINES項目でも使用可能
88 MSG-IS-ERROR VALUE 'ER'.
88 MSG-IS-WARNING VALUE 'WN'.
88 MSG-IS-INFO VALUE 'IN'.
PROCEDURE DIVISION.
MOVE 'ERinvalid ' TO WS-MESSAGE-RAW
IF MSG-IS-ERROR
DISPLAY 'エラー内容: ' WS-MSG-BODY
END-IF.
実践パターン
バッチ処理での入力レコード振り分け
複数レコードタイプが混在するトランザクションファイルを読み込み、レコード種別ごとに処理を振り分ける典型的なバッチパターンです。
IDENTIFICATION DIVISION.
PROGRAM-ID. MULTI-RECORD-PROC.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT TRANS-FILE ASSIGN TO 'TRANS.DAT'
ORGANIZATION IS SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD TRANS-FILE.
01 TRN-RECORD PIC X(80).
WORKING-STORAGE SECTION.
01 WS-EOF PIC X VALUE 'N'.
01 WS-TOTAL-SALES PIC 9(12)V99 VALUE ZERO.
01 WS-ERR-COUNT PIC 9(5) VALUE ZERO.
* 読み込んだレコードを種別別に解釈
01 WS-REC PIC X(80).
01 WS-HDR-REC REDEFINES WS-REC.
05 WS-HDR-TYPE PIC X(1). *> '0'
05 WS-HDR-DATE PIC 9(8).
05 FILLER PIC X(71).
01 WS-DETAIL-REC REDEFINES WS-REC.
05 WS-DTL-TYPE PIC X(1). *> '1'
05 WS-DTL-CODE PIC X(10).
05 WS-DTL-QTY PIC 9(5).
05 WS-DTL-PRICE PIC 9(8)V99.
05 FILLER PIC X(54).
01 WS-TRAIL-REC REDEFINES WS-REC.
05 WS-TRL-TYPE PIC X(1). *> '9'
05 WS-TRL-COUNT PIC 9(7).
05 WS-TRL-TOTAL PIC 9(12)V99.
05 FILLER PIC X(59).
PROCEDURE DIVISION.
OPEN INPUT TRANS-FILE
PERFORM UNTIL WS-EOF = 'Y'
READ TRANS-FILE INTO WS-REC
AT END MOVE 'Y' TO WS-EOF
END-READ
IF WS-EOF NOT = 'Y'
EVALUATE WS-HDR-TYPE
WHEN '0'
DISPLAY '処理日付: ' WS-HDR-DATE
WHEN '1'
COMPUTE WS-TOTAL-SALES =
WS-TOTAL-SALES +
(WS-DTL-QTY * WS-DTL-PRICE)
WHEN '9'
DISPLAY '件数: ' WS-TRL-COUNT
DISPLAY '合計: ' WS-TRL-TOTAL
WHEN OTHER
ADD 1 TO WS-ERR-COUNT
END-EVALUATE
END-IF
END-PERFORM
CLOSE TRANS-FILE
STOP RUN.
入力データのバリデーション前後の共有
外部から受け取った文字列データを、内容に応じて数値として処理するパターンです。ACCEPT文や外部インターフェースで文字列として入力されたデータを変換なしで扱えます。
WORKING-STORAGE SECTION.
01 WS-INPUT-STR PIC X(8). *> 外部から文字列として受取
01 WS-INPUT-NUM REDEFINES WS-INPUT-STR PIC 9(8).
01 WS-TAX PIC 9(9)V99.
01 WS-IS-NUMERIC PIC X VALUE 'N'.
PROCEDURE DIVISION.
ACCEPT WS-INPUT-STR *> 文字列として受け取る
*> 数値かどうかをチェック
IF WS-INPUT-STR IS NUMERIC
MOVE 'Y' TO WS-IS-NUMERIC
END-IF
IF WS-IS-NUMERIC = 'Y'
*> 数値として演算(REDEFINES経由で型変換なし)
COMPUTE WS-TAX = WS-INPUT-NUM * 0.10
DISPLAY '消費税: ' WS-TAX
ELSE
DISPLAY 'エラー: 数値を入力してください'
END-IF.
よくある落とし穴と対策
① VALUE句を書いてコンパイルエラー
症状: REDEFINES句を持つ項目にVALUE句を記述するとコンパイルエラーになります。
対策: 初期値は再定義される側(元の項目)に設定するか、PROCEDURE DIVISIONでMOVEまたはINITIALIZEで初期化します。88レベルの条件名だけは例外でVALUE句が使えます。
② サイズ不一致によるデータ化け
症状: 再定義後の項目のサイズが元の項目と合っていないと、期待したフィールドに別のフィールドのデータが混入します。コンパイラが警告するケースもありますが、実行時のみ症状が出ることもあります。
対策: 再定義する側の全フィールドのバイト数を合計し、元の項目のサイズと一致しているか必ず確認します。FILLERで調整するときは隙間なく埋めてください。
01 WS-ORIG PIC X(10). *> 10バイト
* 合計8バイト(2バイト足りない)→ 動作が不定
01 WS-REDEF REDEFINES WS-ORIG.
05 WS-PART1 PIC X(5).
05 WS-PART2 PIC X(3). *> 5+3=8バイト (10に合わない)
* 正しくはFILLERで埋める
01 WS-REDEF-OK REDEFINES WS-ORIG.
05 WS-PART1 PIC X(5).
05 WS-PART2 PIC X(3).
05 FILLER PIC X(2). *> 合計10バイト
③ チェーンREDEFINESで環境依存の動作
症状: WS-B REDEFINES WS-A の後に WS-C REDEFINES WS-B と書く「チェーン再定義」は、一部のCOBOLコンパイラでは受け入れられますが、規格上は非推奨です。移植性が失われます。
対策: 再定義先は必ず元の基底項目(最初に定義した項目)に統一します。複数の再定義がある場合はすべて同じ基底項目をREDEFINESに指定します。
* NG: WS-Bをさらに再定義(チェーン構造・非推奨) 01 WS-A PIC X(8). 01 WS-B REDEFINES WS-A PIC X(8). 01 WS-C REDEFINES WS-B PIC X(8). *> 非推奨 * OK: すべて基底項目WS-Aに対してREDEFINES 01 WS-A PIC X(8). 01 WS-B REDEFINES WS-A PIC X(8). 01 WS-C REDEFINES WS-A PIC X(8). *> OK
④ 文字⇔数値の混同によるゴミ値
症状: 文字型(PIC X)の項目に数値が入っていないのに、REDEFINESした数値型(PIC 9)で算術演算するとゴミ値や不正データ例外が発生します。
対策: 数値型REDEFINESで演算する前に、元の文字型項目がIS NUMERICクラス条件を満たしているか確認してから使います。
⑤ FILLERの見落としでフィールドがずれる
症状: 固定長レコードの途中にFILLERがあるレイアウトで、REDEFINES定義時にFILLERを省略すると後続フィールドの位置がずれてデータを誤読します。特にレガシーコードの保守で見落としやすいバグです。
対策: 元の項目の総バイト数(FILLERを含む)とREDEFINES後の総バイト数を照合するツールや手動のバイト数チェックを必ず行います。
よくある質問
まとめ
| ポイント | 内容 | 対処・補足 |
|---|---|---|
| 基本 | 同じメモリ領域に複数の名前とレイアウトを定義できる | コピーなし・実行時オーバーヘッドなし |
| VALUE禁止 | REDEFINES項目にはVALUE句を使えない | 88レベル条件名は例外 |
| サイズ一致 | 01以外のレベルでは元の項目とサイズを合わせる | FILLERで調整 |
| OCCURS不可 | OCCURS句を持つ項目のREDEFINESは不可(逆はOK) | 親グループをREDEFINES |
| 複数REDEFINES | 同一基底項目を複数の項目でREDEFINES可 | チェーンは非推奨 |
| FD内 | FD直下の複数01レベルは暗黙REDEFINES | 明示的なREDEFINES不要 |
REDEFINES句は固定長ファイル処理・複数レイアウト対応・日付分解など、COBOLの業務プログラムで欠かせない機能です。サイズ一致とVALUE句の制約を守り、FILLERを正確に合わせることで安全に活用できます。
REDEFINES句を活用したデータ処理をさらに発展させるには、OCCURS句による配列定義やMOVE文のデータ転送ルールも合わせて確認しておくと理解が深まります。
