【実務・中級編】FIXED BINARYの内部表現とストレージ占有量 – PL/Iの基本構文とデータ制御実践ガイド

おい、最近入った若手が「なんかVSAMのキー長を合わせたのに、COBOLから移行したPL/Iのプログラムでデータが化けるんです」って青い顔して駆け込んできたんだよ。

原因を覗いてみたら、案の定 `FIXED BINARY` の精度(precision)の指定をナメてかかっていた。COBOLの `COMP` や `COMP-3` と同じノリで書いていると、IBMメインフレームのPL/Iコンパイラは容赦なく牙をむく。特にストレージの境界(boundary)アライメントと内部表現の仕様を理解していないと、構造体のオフセットがズレまくり、外部ファイルやDB2、CICSとの間で大惨事を引き起こす。

今日は、PL/Iの `FIXED BINARY(p)` が内部でどうメモリを食い、コンパイラがどうストレージを割り当てているのか、現場の泥臭い実例を交えて徹底的に叩き込んでやる。

—

1. 精度 $p$ とストレージ占有量の厳密な関係

PL/Iの固定小数点二進数、すなわち `FIXED BINARY(p)`(略して `FIXED BIN`)を定義するとき、お前らはカッコの中に何を考えて数字を入れている? 「とりあえず桁数だろ」なんて適当に決めているなら今すぐ改めろ。

この $p$(精度:precision)は、符号を含まない「有効二進ビット数」を指している。そして、IBM Enterprise PL/Iコンパイラはこの $p$ の値を見て、メモリ上に確保するバイト数(ストレージ占有量)を機械的に決定する。ここが最大のポイントだ。

  • $p$ が 1 から 15 の場合:

コンパイラはこれを ハーフワード(半語 = 2バイト / 16ビット) として割り当てる。

  • $p$ が 16 から 31 の場合:

コンパイラはこれを フルワード(全語 = 4バイト / 32ビット) として割り当てる。

  • $p$ が 32 から 63 の場合:

コンパイラはこれを ダブルワード(倍語 = 8バイト / 64ビット) として割り当てる(主に `FIXED BIN(63)`、いわゆるロング・ロング整数だ)。

なぜこれが実務で問題になるのか?

COBOL経験者がやりがちなミスだが、例えば `PIC S9(4) COMP` はバイナリで2バイト(16ビット)を専有する。これをPL/Iで `FIXED BINARY(4)` と書いたとする。
おい、ちょっと待て。PL/Iで `FIXED BIN(4)` と書いた場合、$p=4$ は「4ビット」を意味する。しかし、コンパイラはこれをハーフワード(2バイト=16ビット)の領域に格納し、上位ビットは符号拡張(Sign Extension)される。

もし外部のCOBOL製プログラムが純粋な2バイト領域として書き込んだデータを、PL/I側で誤った精度やアライメントで受け取ろうものなら、バイナリの値が全く意図しない数値に化けるか、最悪の場合はコンバージョンエラーやS0C7に近いパニックを引き起こす。

—

2. アライメント(境界調整)の罠と実務上のリスク

メインフレームのアーキテクチャ(System z)では、CPUがメモリからデータをロードする際、2バイト境界、4バイト境界、8バイト境界にデータが綺麗に収まっている方が処理効率が圧倒的に良い。

PL/Iの構造体(`DECLARE`文での `MAJOR STRUCT`)において、要素がどのように並ぶか意識したことがあるか?
コンパイラはデフォルトで、フルワード以上のデータ(`FIXED BIN(16)` 以上、あるいはポインタなど)に出くわすと、メモリ上のアドレスが4の倍数(フルワード境界)になるように暗黙のパディング(隙間・パディングバイト)を挿入する。

これを理解していないと、VSAMファイルや固定長レコード(RECFM=FB)をダイレクトに構造体へ `READ` した際、フィールドの位置が数バイトズレて、日付データや金額データが全く読めなくなるという、夜間バッチの王道エラーを踏むことになる。

—

3. 実践コード:正確なデータ制御とONユニットによる例外処理

百聞は一見に如かずだ。実際にVSAM(KSDS)のレコードレイアウトを想定し、ハーフワードとフルワードの `FIXED BIN` を混在させた構造体の定義、およびデータ溢れ(Overflow)を検知するための `ON CONDITION` の制御フローを含んだ実用的なPL/Iコードを示す。

大文字ベースの美しいコードを体に叩き込め。

1
/
/ MODULE NAME: MIGR001P /
/ DESCRIP: FIXED BINARYのストレージ制御とVSAMレコード入出力サンプル /
/
MIGR001P: PROC OPTIONS(MAIN);

/ VSAMレコードマッピング用構造体の定義 /
/ 外部インターフェース(COBOLや既存資産)との互換性を意識 /
DECLARE
1 VSAM_REC,
/ 15以下なのでハーフワード(2バイト)を占有 /
/ 実際の許容値は -32768 ~ +32767 /
5 REC_ID FIXED BIN(15) VALUE(0),

/ 16以上なのでフルワード(4バイト)を占有 /
/ 大量件数や金額を扱うため4バイト境界にアライメントされる /
5 REC_AMOUNT FIXED BIN(31) VALUE(0),

/ 制御フラグや細かいステータス用(2バイト) /
5 REC_STATUS FIXED BIN(15) VALUE(0),

/ パディングによるズレを防ぐためのパディングエリア /
5 FILLER CHAR(20);

/ ファイル定義 (VSAM KSDSを想定) /
DECLARE VSAM_FILE FILE RECORD
ENV(VSAM);

/ 処理制御用変数 /
DECLARE EOF_FLG CHAR(1) INIT(‘OFF’);

/ — 異常系制御: OVERFLOW条件の捕捉 — /
/ FIXED BINの計算結果が桁あふれを起こした場合のトラップ /
ON OVERFLOW
BEGIN;
PUT SKIP LIST(‘ ERROR: 算術オーバーフローを検知しました ‘);
PUT SKIP LIST(‘現在のREC_ID: ‘, REC_ID);
/ 必要に応じた異常終了コードの設定やロールバック処理を記述 /
SIGNAL FINISH;
END;

/ ファイルオープン /
OPEN FILE(VSAM_FILE) INPUT;

/ 読み込みループ /
DO WHILE(EOF_FLG = ‘OFF’);

READ FILE(VSAM_FILE) INTO(VSAM_REC);

IF ENDFILE(VSAM_FILE) THEN
EOF_FLG = ‘ON’;
ELSE
DO;
/ 組み込み関数(BUILTIN)を活用したデータ検証と処理 /
/ FIXED BIN同士の演算はコンパイラが最適コードを生成する /
IF REC_AMOUNT > 1000000 THEN
DO;
PUT SKIP EDIT
(‘HIGH VALUE RECORD – ID:’, REC_ID,
‘ AMOUNT:’, REC_AMOUNT)
(A, F(6), A, F(10));
END;

/ ビット操作やサイズ確認のデバッグ出力 /
/ STORAGE関数で実際のメモリ占有バイト数を確認可能 /
/ 予備知識: STORAGE(REC_ID) は 2 を返す /
/ 予備知識: STORAGE(REC_AMOUNT) は 4 を返す /
END;

END;

/ ファイルクローズ /
CLOSE FILE(VSAM_FILE);

PUT SKIP LIST(‘MIGR001P NORMAL END.’);

END MIGR001P;

—

4. ベテランからの現場の教訓(デバッグのコツ)

最後に、実際の移行プロジェクトや保守現場でハマりがちな「落とし穴」をいくつか授けておく。

1. 外部連携時の `UNALIGNED` 属性の活用:
もし構造体が外部の古いデータセットや、COBOLと完全にレイアウトを一致させる必要がある場合、デフォルトの境界調整(アライメント)が邪魔をする。その場合は、構造体や変数に `UNALIGNED` 属性を明示的に付与しろ。
`DECLARE 1 VSAM_REC UNALIGNED, …` と書くことで、コンパイラの余計なパディングバイトの挿入を防ぎ、完全に詰まった状態でストレージを確保させることができる。ただし、CPUのアクセス効率は若干落ちるため、パフォーマンスクリティカルな巨大ループ内では注意が必要だ。
2. `STORAGE` ビルトイン関数の活用:
「この変数が今何バイト食っているか不安だ」と思ったら、迷わず `STORAGE(変数名)` を使え。コンパイル時に確定するサイズが即座にわかるため、構造体のオフセット計算で頭を悩ませる時間が劇的に減る。
3. 初期化の徹底:
PL/Iでは `INITIAL`(または `VALUE`)を省略したローカル変数は不定値(ガベージ)を持つ。特に `FIXED BIN` の場合、変なビットパターンが入ったまま演算に使うと、いきなり前述の `OVERFLOW` を踏むか、最悪の場合はサイレント・コラプション(静的なデータ破損)を起こして後続のジョブに毒を回す。必ず初期値を明確にするか、構造体全体をクリアする習慣をつけろ。

基幹システムの命は「正確性」と「予測可能性」だ。データ型とストレージの裏側の仕組みをロジカルに把握していれば、どんな古いレガシーコードが目の前に来ようとも恐れるに足りない。しっかりと手を動かして、体に染み込ませておけよ。

タイトルとURLをコピーしました