【実務・中級編】STRING組み込み関数による構造体・配列の連結 – PL/Iの基本構文とデータ制御実践ガイド

構造体を「ただの文字列」として扱う危うさと美学――STRING関数の真実

古参のメインフレームエンジニアなら一度は経験があるだろう。VSAMファイルへの書き出しや、ネットワーク経由の電文送信時に、「この構造体を丸ごと一発でバッファに詰め込めないか」という誘惑に駆られる瞬間が。

PL/Iには、まさにそのための `STRING` 組み込み関数が存在する。しかし、この関数を「ただの便利ツール」としか認識していないなら、君の書いたバッチプログラムは、ある日突然、不可解なデータ破損という名の地雷を踏むことになる。今日は、そのメカニズムと、現場で生き残るための「アライメント」の作法を語ろう。

1. 予約語なき自由と「STRING」の威力

PL/Iの特筆すべき仕様は、予約語を持たないことだ。`IF` や `THEN` さえも、文脈さえ許せば変数名として使えてしまう(推奨はしないが)。この自由度が、時に保守性を下げ、時に強力なメタプログラミングを可能にする。

その最たる例が `STRING` 関数だ。構造体全体を一つの `CHARACTER` 文字列としてキャストするこの機能は、複雑なインターフェース定義を簡潔に扱うための強力な武器となる。

/i
DCL 1 HEADER_REC,
2 REC_TYPE CHAR(1), / レコード区分 /
2 SEQ_NO FIXED BIN(15), / シーケンス番号 /
2 FILLER CHAR(5); / 詰め物 /

/ 構造体全体を一つの文字列としてコピー /
DCL BUFFER CHAR(9);
BUFFER = STRING(HEADER_REC);

一見すると、この代入は単純明快だ。だが、ここにはメインフレーム特有の「アライメント(整列)」という魔物が潜んでいる。

2. アライメントが引き起こす「見えない隙間」

多くの若手が陥る罠は、構造体のメンバーを並べた際に、コンパイラが勝手に挿入する「パディング(詰め物)」を無視することだ。

特に `FIXED BIN` や `FLOAT` を構造体の中に混ぜて宣言した場合、メインフレームのCPUアーキテクチャに合わせて、境界調整のための数バイトが自動的に挿入されることがある。例えば、`CHAR(1)` の直後に `FIXED BIN(31)` が来ると、コンパイラは効率的なメモリアクセスを行うために、中間に「見えない余白」を置くのだ。

これを `STRING` 関数で連結すると、その「余白」まで含めたビット列が取り出される。外部システム側がそのパディングを考慮していない場合、データは「ズレ」を起こす。

現場での回避策:ALIGNEDとUNALIGNED

この問題を制御するには、構造体宣言時に属性を明示的に指定する癖をつけることだ。

/i
/ パディングを排除し、密に詰める指定 /
DCL 1 DATA_BLOCK UNALIGNED,
2 KEY_CODE CHAR(4),
2 AMOUNT FIXED BIN(31);

/ これにより、STRING関数で生成される文字列は 4 + 4 = 8バイトになる /

`UNALIGNED` を指定すれば、コンパイラはアライメントを無視してメモリを隙間なく詰め込む。バッチ処理で外部ファイルとのI/Oを伴う場合、この指定は必須の教養だ。

3. 実践:VSAM出力での活用とデバッグ

VSAMファイルへ書き出す際、レコード構造を動的に操作したい場合は、以下のようなコーディングが一般的だ。

/i
/ レコード出力処理の例 /
DCL OUT_REC CHAR(100) BASED(P_OUT);
DCL 1 WORK_STRUCT UNALIGNED,
2 ID CHAR(10),
2 DATA CHAR(90);

/ ONユニットによる例外制御の重要性 /
ON CONVERSION BEGIN;
PUT SKIP LIST(‘データ変換エラーが発生しました’);
CALL ABEND_ROUTINE;
END;

/ 構造体を文字列に変換して出力バッファへ /
STRING(WORK_STRUCT) = ‘USER001’ || ‘SOME DATA…’;
WRITE FILE(VSAMFILE) FROM(WORK_STRUCT);

ここで重要なのは、`STRING` 関数が「ビット列の直列化」を行っているという意識を持つことだ。万が一、変換時に期待しないフォーマットが混入した場合は、`ON CONVERSION` ブロックで確実に捕捉しなければならない。

4. ベテランからのアドバイス:保守性のために

最後に、一つだけ忠告がある。`STRING` 関数を使って構造体を一気に変換するコードは、「書くのは楽だが、読むのは苦しい」。

もし、将来的に構造体のメンバーが増減する可能性があるのなら、あまりに広範な構造体を `STRING` で括りすぎるのは避けるべきだ。修正が入るたびに、関連するすべての出力先でレイアウトが崩れていないか確認する手間が発生するからだ。

  • 鉄則1: 外部インターフェースに近い部分でのみ `STRING` を使う。
  • 鉄則2: メモリレイアウトの可視化のために、構造体は必ず `UNALIGNED` で定義する。
  • 鉄則3: `DCL` 文のコメントには、必ずバイト長をメモしておく。

PL/Iは、古いがゆえに、現代の言語が隠蔽してしまった「メモリの物理的な姿」を制御できる。その自由を使いこなせるかどうかは、君がコンパイラの挙動をどこまで理解しているかに懸かっている。

現場で躓いたら、まずは `STORAGE` 関数や `ADDR` 関数でメモリの状態を覗いてみることだ。メインフレームの神は、細部に宿る。健闘を祈る。

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