PL/Iの「柔軟さ」という名の深淵:CHARACTER VARYINGのメモリ構造と、マイグレーションの現場で死なないための知見
汎用機の世界では、PL/Iは「最強の汎用言語」として君臨してきた。C言語のようなハードウェアに近い制御性と、COBOLのような強力なビジネス演算能力、そして何より、予約語を持たないという極めてユニークな設計思想。だが、この「何でもあり」の柔軟さは、現代のJavaやC#の堅牢なメモリ管理に慣れた若手エンジニアや、マイグレーションを担うアーキテクトにとっては、時として致命的な落とし穴となる。
今日は、その中でも特に扱いが難しい「`CHARACTER`型と`VARYING`属性」の裏側を、メインフレームの内部構造の視点から解剖してみよう。
—
1. 固定長か、可変長か:メモリレイアウトの物理構造
まずは基本を押さえる。`CHAR(10)`と`CHAR(10) VARYING`では、コンパイラが生成するメモリ領域の定義が根本から異なる。
- `CHAR(10)`: 10バイトの連続した領域を確保する。シンプルだ。
- `CHAR(10) VARYING`: 内部的には12バイト(またはそれ以上、アライメントによる)を占有する。先頭2バイトが「現在の長さ(Length Prefix)」を表すヘッダとして機能し、続く10バイトが実データ領域となる。
/i
DCL FIXED_STR CHAR(10) INIT(‘IBM’); / 10バイト中、残りは自動的に空白で埋まる /
DCL VARY_STR CHAR(10) VARYING INIT(‘IBM’); / 先頭2バイトに3が格納され、後ろに’IBM’が続く /
なぜこれがマイグレーションで問題になるのか
Javaの`String`クラスはイミュータブル(不変)なオブジェクトだが、PL/Iの`VARYING`変数は、代入のたびに長さフィールドが書き換わり、メモリの断片化や、最悪の場合は後続の変数を巻き込むオーバーライトを引き起こす。特に外部システム(CICSのCOMMAREA経由など)とのやり取りで、この「2バイトの長さ情報」を正しく解釈せずにデータを送受信すると、文字化けやシステム異常(ABEND)の温床となるのだ。
—
2. アベンド(ABEND)を回避するためのポインタ操作
基幹システムのバッチ処理で、巨大なバッファを動的に扱う際、`VARYING`のオーバーヘッドを嫌ってあえて固定長で運用し、ポインタで操作する手法が好まれることがある。
/i
DCL BUF_PTR PTR;
DCL 1 BUF_STR BASED(BUF_PTR),
2 LEN FIXED BIN(15), / 長さを手動管理 /
2 DATA CHAR(32767); / 最大長まで確保 /
/ 動的確保によるメモリ効率化 /
ALLOCATE BUF_STR;
BUF_STR.LEN = 5;
SUBSTR(BUF_STR.DATA, 1, 5) = ‘HELLO’;
この手法の肝は、コンパイラ任せにせず、メモリ領域を自前で制御することにある。しかし、ここで注意すべきは「パックデシマルの内部符号反転」だ。データベース(DB2等)から抽出した値をこのバッファに詰め込む際、`PIC S9(7) COMP-3`が意図せず符号(F/C/D)を崩して格納されるバグが散見される。特にEBCDICコードページ環境での移行時は、`HEX`ダンプを確認し、コンパイラの最適化オプション(`OPT(2)`や`TEST`オプション)がメモリの配置にどう影響しているかを追いかける覚悟が必要だ。
—
3. 現場のアーキテクトが教える、マイグレーションの「エッジケース」
CICS環境でのPL/I移行において、最も恐ろしいのは「ポインタの有効範囲」だ。
- ポインタの迷子: `BASED`変数を使用している場合、`FREE`した後のポインタを無意識に参照し続けても、PL/Iは即座にエラーを出さないことが多い。これが本番環境で断続的に発生する「再帰的なABEND(S0C4など)」の原因となる。
- 最適化の罠: `OPTIMIZE`オプションを上げると、コンパイラは「この変数はループ内で変化しない」と判断し、レジスタに値をキャッシュする。しかし、別セグメントからそのメモリが書き換えられていた場合、プログラムは古い値を参照し続ける。これを防ぐには、揮発性の高い変数には `AUTOMATIC` や `DEFINED` を慎重に使い分け、外部からのメモリ操作には `STATIC` や `EXTERNAL` のスコープを厳密に管理する必要がある。
—
結論:コードの背後にある「呼吸」を感じろ
PL/Iを扱うということは、単に構文を覚えることではない。コンパイラがどの命令セット(z/Architecture)を生成し、メモリのどこに値を配置し、CPUがどのキャッシュラインを叩いているかを想像することだ。
もしあなたが今、レガシーシステムの移行という困難なプロジェクトを率いているなら、ツールが生成する変換コードを鵜呑みにしてはいけない。`VARYING`の2バイトが持つ重み、ポインタが指し示す先にある物理的なメモリの断片。それら一つひとつに「なぜその設計なのか」という歴史的な必然性が隠されている。
技術とは、美しいコードを書くことではなく、現場で発生する「不可解なバグ」という名のノイズの中から、確実な真実を拾い上げることにある。PL/Iという深淵は、それを理解しようとする者に対してのみ、その強大な力を貸し与えてくれるはずだ。
