【COBOL】MOVE文でデータを転送する|型変換・フィギュアリティブ・CORRESPONDING・編集項目・落とし穴完全ガイド

COBOLで最も頻繁に使う命令文のひとつが MOVE です。「データを転送する」という単純な命令ですが、転送元と転送先のデータ型・桁数が異なるときの挙動を正確に理解していないと、切り捨て・ゼロ埋め・符号消失といったバグを生み出してしまいます。

本記事では基本構文から、数値型・文字型間の型変換ルール、フィギュアリティブコンスタント、MOVE CORRESPONDING、数値編集項目への転送、よくある落とし穴まで、MOVE文のすべてを解説します。

この記事でわかること

  • MOVE文の基本構文と複数ターゲットへの一括転送
  • 数値→数値・文字→文字・数値→文字・文字→数値の型変換ルール
  • ZERO・SPACE・HIGH-VALUE・ALL など特殊フィギュアリティブの使い方
  • MOVE CORRESPONDING(CORR)で同名フィールドを一括転送する方法
  • グループ項目(01レベル)へのMOVEの注意点
  • 数値編集項目(PIC ZZZ,ZZ9 等)への転送で帳票形式に整形する方法
  • 符号消失・桁欠け・上書き漏れなどよくある落とし穴
スポンサーリンク

MOVE文の基本構文

基本構文
       *> 1対1の転送
       MOVE 転送元 TO 転送先

       *> 1対多の転送(複数ターゲットに同時代入)
       MOVE 転送元 TO 転送先-1 転送先-2 転送先-3

       *> リテラル値の転送
       MOVE "HELLO" TO WS-MSG
       MOVE 12345  TO WS-NUM
       MOVE ZERO   TO WS-COUNTER  *> フィギュアリティブ
基本例
       01  WS-NAME-SRC   PIC X(20) VALUE "TANAKA TARO".
       01  WS-NAME-DEST1 PIC X(20).
       01  WS-NAME-DEST2 PIC X(20).
       01  WS-AMT-SRC    PIC 9(7)  VALUE 1500000.
       01  WS-AMT-DEST   PIC 9(7).

       *> 文字列の転送
       MOVE WS-NAME-SRC TO WS-NAME-DEST1 WS-NAME-DEST2

       *> 数値の転送
       MOVE WS-AMT-SRC  TO WS-AMT-DEST
       *> → WS-NAME-DEST1 = WS-NAME-DEST2 = "TANAKA TARO"
       *> → WS-AMT-DEST = 1500000

データ型ごとの転送ルール

MOVEの動作はデータ型の組み合わせによって変わります。各パターンのルールを正確に把握しておくことが重要です。

文字型(X)→ 文字型(X):左寄せ・スペース埋め

文字型から文字型への転送は左寄せで行われます。転送先が長い場合は右側がスペースで埋まり、転送先が短い場合は右側が切り捨てられます。

文字型 → 文字型
       01  WS-SRC  PIC X(10) VALUE "ABCDE".
       01  WS-L15  PIC X(15).  *> 転送先が長い
       01  WS-L03  PIC X(3).   *> 転送先が短い

       MOVE WS-SRC TO WS-L15
       *> WS-L15 = "ABCDE          " (右5文字がスペース)

       MOVE WS-SRC TO WS-L03
       *> WS-L03 = "ABC" (右7文字が切り捨て)

数値型(9)→ 数値型(9):右寄せ・ゼロ埋め

数値型から数値型への転送は右寄せです。転送先が大きい場合は左側がゼロで埋まり、転送先が小さい場合は上位桁が切り捨てられます(SIZE ERRORは発生しない)

数値型 → 数値型
       01  WS-NUM5   PIC 9(5) VALUE 12345.
       01  WS-NUM8   PIC 9(8). *> 転送先が大きい
       01  WS-NUM3   PIC 9(3). *> 転送先が小さい

       MOVE WS-NUM5 TO WS-NUM8
       *> WS-NUM8 = 00012345 (左3桁がゼロ埋め)

       MOVE WS-NUM5 TO WS-NUM3
       *> WS-NUM3 = 345 (上位2桁 "12" が切り捨て)!
MOVE での桁あふれは SIZE ERROR にならない
COMPUTE文の ON SIZE ERROR と異なり、MOVE文では転送先の桁数を超えても例外は発生しません。上位桁が静かに切り捨てられるだけです。桁数が足りるか必ず確認してから MOVE してください。

小数を含む数値型の転送

小数点位置の異なる転送
       01  WS-SRC    PIC 9(5)V99  VALUE 12345.67.
       01  WS-DEST1  PIC 9(7)V99.  *> 整数部が広い
       01  WS-DEST2  PIC 9(3)V9.   *> 小数部が狭い
       01  WS-DEST3  PIC 9(3).     *> 小数部なし

       MOVE WS-SRC TO WS-DEST1
       *> WS-DEST1 = 0012345.67 (整数部左にゼロ埋め)

       MOVE WS-SRC TO WS-DEST2
       *> WS-DEST2 = 345.6 (整数部上位切り捨て・小数部切り捨て)

       MOVE WS-SRC TO WS-DEST3
       *> WS-DEST3 = 345 (小数部切り捨て・整数上位切り捨て)

数値型 → 文字型:ゾーン変換

数値をそのまま文字型に転送すると、ゾーン形式の内部表現が文字列として格納されます。表示用の変換には数値編集項目(後述)を使うのが正しい方法です。

数値 → 文字(注意が必要)
       01  WS-NUM   PIC 9(5) VALUE 12345.
       01  WS-CHAR  PIC X(5).
       01  WS-EDIT  PIC Z(4)9.  *> 数値編集項目

       *> NG: 数値→文字型直接転送(実装依存・意図しない結果になることがある)
       MOVE WS-NUM TO WS-CHAR

       *> OK: 数値編集項目に転送して文字として扱う
       MOVE WS-NUM TO WS-EDIT
       *> WS-EDIT = " 2345" (先頭のゼロをスペースに変換)

フィギュアリティブコンスタント

COBOLには特殊な意味を持つ予約語「フィギュアリティブコンスタント」があります。初期化・クリア処理でよく使います。

フィギュアリティブ 主な用途
ZERO / ZEROS / ZEROES 0(数値)またはスペース(文字) 数値カウンタ・金額の初期化
SPACE / SPACES 半角スペース(X’40’) 文字項目のクリア
HIGH-VALUE / HIGH-VALUES X’FF’(最大バイト値) 検索終端マーク・最大値判定
LOW-VALUE / LOW-VALUES X’00’(最小バイト値) バイナリデータの初期化
ALL "文字" 指定文字で埋め尽くす 区切り線・マスク文字
NULL / NULLS X’00’(ポインタ) ポインタ変数の初期化
フィギュアリティブコンスタントの使い方
       01  WS-COUNTER   PIC 9(5).
       01  WS-AMOUNT    PIC S9(9)V99  COMP-3.
       01  WS-NAME      PIC X(20).
       01  WS-FLAG      PIC X(1).
       01  WS-SEPARATOR PIC X(40).

       *> 数値項目をゼロ初期化
       MOVE ZERO   TO WS-COUNTER
       MOVE ZEROS  TO WS-AMOUNT

       *> 文字項目をスペースクリア
       MOVE SPACES TO WS-NAME

       *> HIGH-VALUE を検索終端マークとして使う
       MOVE HIGH-VALUE TO WS-FLAG

       *> ALL で区切り線を生成
       MOVE ALL "-" TO WS-SEPARATOR
       *> → WS-SEPARATOR = "----------------------------------------"
ZERO と SPACE はデータ型に応じて自動適用される
MOVE ZERO TO WS-NUM(数値)→ 0 が格納されます。
MOVE ZERO TO WS-CHAR(文字)→ スペースが格納されます(文字の “0” ではありません)。
MOVE SPACE TO WS-NUM(数値)→ 0 が格納されます(数値のゼロとして扱われる)。
フィギュアリティブはデータ型に合わせて自動解釈されます。

MOVE CORRESPONDING(CORR):同名フィールドの一括転送

MOVE CORRESPONDING(略して MOVE CORR)は、転送元グループ項目と転送先グループ項目の中に同じ名前の従属項目がある場合、それらをまとめて一括転送します。

MOVE CORRESPONDING の基本例
       01  WS-INPUT.
           05  WS-NAME      PIC X(20).
           05  WS-BIRTHDATE PIC 9(8).
           05  WS-DEPT-CODE PIC X(4).
           05  WS-INPUT-FLG PIC X(1).  *> 転送先にはない

       01  WS-RECORD.
           05  WS-NAME      PIC X(20).
           05  WS-BIRTHDATE PIC 9(8).
           05  WS-DEPT-CODE PIC X(4).
           05  WS-SEQ-NO    PIC 9(6).  *> 転送元にはない

       *> 同名フィールド(NAME・BIRTHDATE・DEPT-CODE)を一括転送
       MOVE CORRESPONDING WS-INPUT TO WS-RECORD
       *> = MOVE WS-NAME      OF WS-INPUT TO WS-NAME      OF WS-RECORD
       *>   MOVE WS-BIRTHDATE OF WS-INPUT TO WS-BIRTHDATE OF WS-RECORD
       *>   MOVE WS-DEPT-CODE OF WS-INPUT TO WS-DEPT-CODE OF WS-RECORD
       *>   WS-INPUT-FLG と WS-SEQ-NO は対象外(片方にしかない)
MOVE CORR vs 個別 MOVE の比較
       *> ---- MOVE CORR なしの場合(9行必要)----
       MOVE WS-NAME      OF WS-INPUT TO WS-NAME      OF WS-RECORD
       MOVE WS-BIRTHDATE OF WS-INPUT TO WS-BIRTHDATE OF WS-RECORD
       MOVE WS-DEPT-CODE OF WS-INPUT TO WS-DEPT-CODE OF WS-RECORD

       *> ---- MOVE CORR ありの場合(1行)----
       MOVE CORRESPONDING WS-INPUT TO WS-RECORD
MOVE CORRESPONDING の注意点
① 名前が同じでもデータ型・桁数が違うフィールドも転送されます(型変換は通常のMOVEと同じルールで行われます)。
② 名前の一致はグループ項目内の直接の従属項目のみが対象です(さらに下の階層は再帰的には探しません)。
③ フィールド数が多い構造での使用は、どのフィールドが転送されるか追いにくくなるため、保守性に注意してください。

グループ項目へのMOVE:バイト単位コピー

グループ項目(01レベルや05レベルなど、従属項目を持つ項目)に対して MOVE を行うと、型変換なしのバイト単位コピーが行われます。転送先の型は一切考慮されません。

グループ項目へのMOVE(バイト単位コピー)
       01  WS-REC-A.
           05  WS-CODE-A    PIC X(4)  VALUE "2024".
           05  WS-AMOUNT-A  PIC 9(6)  VALUE 123456.

       01  WS-REC-B.
           05  WS-CODE-B    PIC X(4).
           05  WS-AMOUNT-B  PIC 9(6).

       *> グループ項目同士のMOVE → バイト単位コピー
       MOVE WS-REC-A TO WS-REC-B
       *> WS-CODE-B = "2024", WS-AMOUNT-B = 123456

       *> 警告: 構造が異なるグループ間のMOVEは意図しない結果になりやすい
       01  WS-REC-C.
           05  WS-C-DATE    PIC 9(8).   *> 8桁数値
           05  WS-C-FLAG    PIC X(2).   *> 2桁文字

       MOVE WS-REC-A TO WS-REC-C  *> A(10バイト)→C(10バイト)をバイトコピー
       *> WS-C-DATE の内部表現がWS-CODE-Aの文字コードになる → 注意

数値編集項目への MOVE:帳票形式に整形する

COBOLの数値編集項目(Edited Numeric)は、数値を表示用に整形するための専用のPICTURE句です。MOVEで代入すると自動的に整形されます。

PIC句 編集文字 値: 1234567 意味
PIC 9(7) なし(非編集) 1234567 そのまま
PIC Z(6)9 Z:先頭ゼロ→スペース 234567 先頭ゼロ抑制
PIC ZZZ,ZZ9 Z+カンマ 1,234,567 3桁カンマ区切り
PIC +ZZZ,ZZ9 符号付き +1,234,567 符号を表示
PIC -ZZZ,ZZ9 マイナス符号 1,234,567 負のとき – を表示
PIC ZZZ,ZZ9.99 小数点付き 1,234,567.00 小数点表示
数値編集項目への MOVE 実例
       01  WS-AMOUNT       PIC S9(7)V99  COMP-3  VALUE 1234567.89.
       01  WS-DISP-BASIC   PIC 9(7).
       01  WS-DISP-Z       PIC Z(6)9.
       01  WS-DISP-COMMA   PIC ZZZ,ZZZ,ZZ9.
       01  WS-DISP-SIGN    PIC +ZZZ,ZZZ,ZZ9.
       01  WS-DISP-DECIMAL PIC ZZZ,ZZZ,ZZ9.99.

       MOVE WS-AMOUNT TO WS-DISP-BASIC
       DISPLAY WS-DISP-BASIC    *>  "1234567"

       MOVE WS-AMOUNT TO WS-DISP-Z
       DISPLAY WS-DISP-Z        *>  "1234567" (先頭ゼロ → スペース変換)

       MOVE WS-AMOUNT TO WS-DISP-COMMA
       DISPLAY WS-DISP-COMMA    *>  "  1,234,567"

       MOVE WS-AMOUNT TO WS-DISP-DECIMAL
       DISPLAY WS-DISP-DECIMAL  *>  "1,234,567.89"
数値編集項目はバックへの転送不可
数値編集項目(PIC ZZZ,ZZ9 等)から通常の数値項目(PIC 9(n))へ逆方向にMOVEすることはできません(コンパイルエラー)。帳票出力用の一方向変換として使います。計算には必ず元の非編集数値項目を使ってください。

よくある落とし穴と対策

落とし穴1:符号なし変数へのマイナス値転送

符号なし変数に負の値をMOVE
       01  WS-SIGNED   PIC S9(5)  VALUE -500.
       01  WS-UNSIGNED PIC 9(5).   *> 符号なし

       MOVE WS-SIGNED TO WS-UNSIGNED
       *> 結果は実装依存(符号が失われ絶対値になるか、00500になるか)
       *> GnuCOBOL: WS-UNSIGNED = 00500 (符号消失)

       *> 対策: 必ず PIC S9(n) で符号付き宣言する
       01  WS-DEST-SIGNED PIC S9(5).
       MOVE WS-SIGNED TO WS-DEST-SIGNED  *> OK

落とし穴2:グループ項目の上書きによるフィールド破損

グループ項目MOVEで意図しないフィールドを上書き
       01  WS-DATE-GROUP.
           05  WS-YEAR    PIC 9(4).
           05  WS-MONTH   PIC 9(2).
           05  WS-DAY     PIC 9(2).

       01  WS-DATE-INIT   PIC X(8) VALUE "00000000".

       *> グループ項目全体を一括クリアしたいとき
       MOVE "00000000" TO WS-DATE-GROUP  *> グループをバイト単位でクリア

       *> より安全な方法: 個別フィールドをMOVE ZERO
       MOVE ZERO TO WS-YEAR
       MOVE ZERO TO WS-MONTH
       MOVE ZERO TO WS-DAY

       *> または INITIALIZE を使う(詳細は別記事参照)
       INITIALIZE WS-DATE-GROUP

落とし穴3:MOVE 後に元の値が残ったと思い込む

MOVEはコピー(元は変化しない)
       01  WS-SRC  PIC X(10) VALUE "ORIGINAL".
       01  WS-DEST PIC X(10).

       MOVE WS-SRC TO WS-DEST
       *> WS-DEST = "ORIGINAL"
       *> WS-SRC  = "ORIGINAL" ← 変化しない

       *> MOVEはコピー操作。元データは失われない。
       *> 「転送」という言葉のイメージに惑わされないこと

実践パターン集

パターン1:帳票出力用のレコード整形

帳票出力レコードへのデータセット
       01  WS-SALES-DATA.
           05  WS-ITEM-CODE  PIC X(10).
           05  WS-ITEM-NAME  PIC X(30).
           05  WS-UNIT-PRICE PIC S9(7)V99  COMP-3.
           05  WS-QTY        PIC S9(5)     COMP-3.
           05  WS-SUBTOTAL   PIC S9(9)V99  COMP-3.

       01  WS-PRINT-LINE.
           05  PL-ITEM-CODE  PIC X(10).
           05  FILLER        PIC X(2)  VALUE SPACES.
           05  PL-ITEM-NAME  PIC X(30).
           05  FILLER        PIC X(2)  VALUE SPACES.
           05  PL-UNIT-PRICE PIC ZZZ,ZZZ,ZZ9.
           05  FILLER        PIC X(2)  VALUE SPACES.
           05  PL-QTY        PIC ZZZ,ZZ9.
           05  FILLER        PIC X(2)  VALUE SPACES.
           05  PL-SUBTOTAL   PIC ZZZ,ZZZ,ZZZ,ZZ9.

           *> 数値→数値編集項目へMOVE(自動整形)
           MOVE WS-ITEM-CODE  TO PL-ITEM-CODE
           MOVE WS-ITEM-NAME  TO PL-ITEM-NAME
           MOVE WS-UNIT-PRICE TO PL-UNIT-PRICE
           MOVE WS-QTY        TO PL-QTY
           MOVE WS-SUBTOTAL   TO PL-SUBTOTAL
           WRITE PRINT-RECORD FROM WS-PRINT-LINE

パターン2:ループ前の作業域一括初期化

ループ内で使う作業域をまとめて初期化
       01  WS-WORK-AREA.
           05  WS-W-CODE     PIC X(10).
           05  WS-W-NAME     PIC X(30).
           05  WS-W-AMOUNT   PIC S9(9)V99  COMP-3.
           05  WS-W-COUNT    PIC S9(5)     COMP-3.
           05  WS-W-ERR-FLG  PIC X(1).

       PERFORM VARYING WS-IDX FROM 1 BY 1
           UNTIL WS-IDX > WS-MAX
           *> ループ先頭で作業域を一括クリア
           MOVE SPACES TO WS-W-CODE WS-W-NAME WS-W-ERR-FLG
           MOVE ZEROS  TO WS-W-AMOUNT WS-W-COUNT
           *> 処理本体
           PERFORM MAIN-LOGIC
       END-PERFORM

パターン3:入力レコードから出力レコードへのCORR一括転送

ファイルレコードから出力レコードへ CORR で一括転送
       01  FS-INPUT-RECORD.
           05  FS-CUST-ID    PIC X(8).
           05  FS-CUST-NAME  PIC X(30).
           05  FS-BIRTH-DATE PIC 9(8).
           05  FS-INPUT-DATE PIC 9(8).  *> 出力には不要

       01  WS-OUTPUT-RECORD.
           05  FS-CUST-ID    PIC X(8).
           05  FS-CUST-NAME  PIC X(30).
           05  FS-BIRTH-DATE PIC 9(8).
           05  WS-PROC-DATE  PIC 9(8).  *> 入力にはない(処理日を別途設定)

       *> 同名フィールドを一括転送(INPUT-DATE と PROC-DATE は対象外)
       MOVE CORRESPONDING FS-INPUT-RECORD TO WS-OUTPUT-RECORD
       *> 処理日は別途設定
       MOVE WS-TODAY TO WS-PROC-DATE

MOVE vs INITIALIZE の使い分け

用途 推奨手段 理由
特定フィールドに特定値を代入 MOVE 対象と値を明示できる
グループ項目内を型に応じてゼロ/スペースに初期化 INITIALIZE 数値→0、文字→スペースを自動適用
グループ項目全体を同じ文字で埋める MOVE SPACESなど バイト単位の一律クリアができる
特定フィールドのみ初期化(残りは保持) MOVE INITIALIZEは対象グループ全体に適用される

よくある質問

QMOVE と SET の違いは何ですか?
A88レベル条件名に値をセットする場合は MOVE ではなく SET を使います。例えば SET IS-ACTIVE TO TRUE は、IS-ACTIVEに対応する親変数に VALUE で定義した値を代入します。条件名に対して MOVE を使うとコンパイルエラーになります。
QMOVE CORRESPONDING は何階層まで対応しますか?
AMOVE CORRESPONDING は直接の従属項目(1階層下)のみを対象とします。ただし従属項目がさらに下位を持つグループ項目の場合、そのグループ項目同士が同名なら再帰的に CORRESPONDING が適用されます。詳細な動作はコンパイラの実装に依存する部分があるため、深い階層での MOVE CORR は慎重に使ってください。
QMOVE SPACE と MOVE SPACES はどちらを使えばいいですか?
Aどちらでも意味は同じです。SPACE・SPACES・ZERO・ZEROS・ZEROES は複数形も単数形も同一のフィギュアリティブコンスタントです。チームやプロジェクトの規約に合わせて統一してください。
QMOVE で桁あふれを検知する方法はありますか?
AMOVE 文自体には SIZE ERROR の仕組みがありません。桁あふれを防ぐには①事前に転送元の値の範囲を確認する、②転送先の桁数を十分大きく定義する、という設計で対処します。桁あふれが問題になる計算結果を格納する場合は COMPUTE の ON SIZE ERROR 句を使ってください。
QFILLER 項目には MOVE できますか?
AFILLER は名前でアクセスできません(名前なし項目のため)。FILLER に値を設定したい場合は、FILLER ではなく適切な名前を付けてから MOVE してください。ただし MOVE を使わずに FILLER PIC X(2) VALUE " ". のように定義時に初期値を設定する方法が一般的です。

まとめ

MOVE文のポイントをまとめます。

  • 文字型(X):左寄せ・右スペース埋め・右切り捨て
  • 数値型(9):右寄せ・左ゼロ埋め・左切り捨て(SIZE ERRORなし)
  • フィギュアリティブ:ZERO・SPACE・HIGH-VALUE・ALL “X” を用途に応じて使い分け
  • MOVE CORRESPONDING:同名フィールドを一括転送。型変換は通常のMOVEと同じルール
  • グループ項目:バイト単位コピーのため型変換なし。構造が異なると意図しない結果になる
  • 数値編集項目:帳票用の表示形式(カンマ・ゼロ抑制)への一方向変換
  • 落とし穴:符号消失・桁切り捨て・バイト単位グループ上書きに注意

関連記事:INITIALIZE文を使ってデータ項目を初期化する方法COMPUTEで計算を行う(ROUNDED・ON SIZE ERROR)REDEFINES句で項目を再定義する方法DISPLAY文で画面にメッセージやデータを表示させる方法