こんにちは!メインフレームの世界へようこそ。
JavaやCOBOLといった他のプログラミング言語の経験がおありなら、新しい言語を学ぶときのワクワク感と、「あれ、これどういうことだ?」という独特の戸惑いが入り混じっている頃ではないでしょうか。
特にIBMのメインフレームで現役バリバリ動いているPL/I(ピーエルアイ)は、その歴史の深さゆえに、現代の言語とはちょっと違った「ぶっ飛んだ」内部仕様を持っていたりします。
でも、安心してくださいね。「レガシーだから難解」「何か呪文のようにおっかない仕様がある」なんて構える必要は全くありません。一つひとつ、フタを開けて中身を覗いていけば、「なーんだ、そういうことか!」とスッキリ腑に落ちるはずです。
今回は、そんなPL/Iのデータ制御の中でも、初学者が思わず「おや?」とつまずきがちな`VARYING`属性の内部構造について、エンジニアの先輩がこっそり教えるような気持ちで、優しく紐解いていきたいと思います。
—
1. 可変長文字列(VARYING)って、一体中でどうなっているの?
Javaでいえば `String` や `StringBuilder`、COBOLなら `USAGE IS INDEX` を伴う可変長項目(`PIC X(50) DEPENDING ON …`)をイメージしてください。これらに相当するのが、PL/Iの `CHARACTER (50) VARYING` という宣言です。
固定長の `CHARACTER (50)` であれば、宣言した瞬間にメモリ上でピッタリ50バイトの領域が確保されます。これは分かりやすいですよね。
では、`VARYING` を付けるとどうなるでしょうか? 「あ、文字数に合わせてメモリの大きさが可変になるんだな」というのは直感的にわかると思います。
しかし、ここでJavaやCOBOL出身のエンジニアがハッとするPL/Iのリアルな内部事情があります。
実は、コンパイラはメモリをいい感じに伸縮させているわけではありません。「あらかじめ最大サイズ(この場合は50バイト)分の入れ物を用意しつつ、その手前に小さな『番頭さん』を配置している」のです。
この「番頭さん」の正体こそが、先頭の2バイトに格納される長さ情報(プレフィックス)です。
メモリのイメージ図
[ 実際のデータ領域 (最大50バイト) ]
↓
+——–+—————————————–+
| 長さ | 文字データ… |
| (2Byte)| |
+——–+—————————————–+
文字データに `”IBM”` という3文字を代入したとします。このとき、メモリの先頭2バイトにはバイナリ形式で「3(X’0003’)」という数字が書き込まれます。その後ろに `”IBM”` が続き、残りの領域は使われない(あるいは以前のゴミが残っている)状態になります。
「えっ、じゃあ最大長を超えて文字を入れたらどうなるの?」
……はい、そこはメインフレームの厳しい世界。バッファオーバーフローやデータ破損のリスクに直結しますので、宣言した最大長(この場合は50)という枠のなかで、この「番頭さん(長さ情報)」が上手に管理を行っているわけです。
—
2. 百聞は一見にしかず!PL/Iコードで挙動を見てみよう
実際に、この `VARYING` 属性を持った変数を宣言し、どのように扱われるのかを簡単なPL/Iのサンプルコードで見てみましょう。
実務のバッチプログラムやマイグレーション調査でそのまま参考にしていただけるよう、大文字ベースで記述しています。
- VARYING属性の変数を定義し、内部の長さを確認するサンプルプログラム
VARYING_SAMPLE: PROC OPTIONS(MAIN);
/ 最大50バイトの可変長文字列変数の宣言 /
DCL MSG_AREA CHAR(50) VARYING;
/ 数値制御用の変数 /
DCL DATA_LEN FIXED BIN(15);
/ 1. 文字列を代入してみる /
MSG_AREA = ‘HELLO, MAINY!’;
/ 2. 現在の格納文字数を LENGTH 組み込み関数で取得 /
DATA_LEN = LENGTH(MSG_AREA);
/ 3. 結果をsysoutに出力(実際の商用機ではPUT SKIP LISTなどを使用) /
PUT SKIP EDIT (‘文字数: ‘, DATA_LEN) (A, F(5));
PUT SKIP EDIT (‘文字列: ‘, MSG_AREA) (A, A);
/ 4. より長い文字列を代入して上書き /
MSG_AREA = ‘Welcome to the IBM Mainframe World with PL/I!’;
DATA_LEN = LENGTH(MSG_AREA);
PUT SKIP EDIT (‘変更後 文字数: ‘, DATA_LEN) (A, F(5));
PUT SKIP EDIT (‘変更後 文字列: ‘, MSG_AREA) (A, A);
END VARYING_SAMPLE;
このコードのポイント
- `CHAR(50) VARYING` と宣言することで、最大50バイトまでの可変長文字列を作っています。
- `LENGTH(MSG_AREA)` という組み込み関数を呼ぶと、PL/Iは先頭2バイトの「番頭さん(長さ情報)」を瞬時に読み取り、現在の実際の文字数を返してくれます。Javaの `length()` メソッドと同じ感覚で使えますが、その裏ではコンパイラが機械語レベルでこの2バイトの長さを参照しているのです。
—
3. なぜ「先頭2バイト」なのか?(アーキテクチャの深い話)
ここで少しだけ、メインフレームの歴史とアーキテクチャに踏み込んでみましょう。
「なぜ長さ情報は4バイトでも1バイトでもなく、2バイト(半ワード / ハーフワード)なのか?」
それは、IBM System/360以降のアーキテクチャにおいて、2バイトの整数(`FIXED BIN(15)` や `H` 形式)が、CPUの演算命令(レジスタへのロードやストア)において最も効率よく扱える基本単位の一つだったからです。
PL/Iは1960年代にIBMで誕生した言語ですが、当時のハードウェアの制約と性能を極限まで引き出すために、「可変長文字列の長さを表現するには、2バイトの整数領域を先頭に持たせるのが一番効率が良い」という設計思想が採用されました。
この仕様は、半世紀以上経った現代の最新型メインフレーム(IBM z16など)のコンパイラでも、下位互換性を保ったまま脈々と受け継がれています。レガシーシステムの底知れぬロマンを感じませんか?
—
4. 他言語経験者がハマりやすい「注意点」と実務の知恵
さて、この `VARYING` の制御ブロック構造を知っておくと、実務で他の言語から移行してきたときによくある「あるあるトラブル」を防ぐことができます。
1. 外部ファイルやDB2とのやり取りでの罠
- COBOLの可変長(OCCURS … DEPENDING ONや、S9(4) COMPで長さを表すような構造)とデータをファイル経由でやり取りする場合、PL/Iの `VARYING` が持つ先頭2バイトの長さ領域がそのまま出力ファイルに含まれるか、あるいは邪魔になることがあります。
- 外部連携インターフェースの設計では、「本当に `VARYING` を使うべきか、それともパディング(空白埋め)を許容する `CHARACTER` 固定長で設計すべきか」を慎重に判断する必要があります。
2. ポインタやストレージ管理(Based変数)との組み合わせ
- PL/Iの真骨頂は、ポインタを使った高度なメモリ操作(`BASED` 属性)にあります。もしあなたがシステムの深層で動的メモリ管理を行うコードを書くことになっても、「あ、先頭の2バイトは長さが入っているから、実際のデータ本体はそのオフセットの2バイト先から始まるんだな」ということが分かっていれば、メモリダンプ(CWDやスナップショット)を見たときにも怯えることはありません。
—
まとめ
いかがでしたでしょうか?
一見すると古めかしく難解に見えるPL/Iの `VARYING` 属性も、その中身を紐解けば「最大サイズの中にデータ本体と、先頭2バイトの番頭さん(長さ情報)が仲良く同居しているシンプルな構造」であることがお分かりいただけたかと思います。
メインフレームの世界は、こうしたハードウェアの歴史と密接に結びついた美しい設計思想で満ち溢れています。「怖くないですよ、一つずつ紐解けば簡単です」。このブログが、あなたのレガシーシステム開発・移行の不安を少しでも和らげ、頼もしい相棒を見つけるきっかけになれば幸いです。
それでは、次回のPL/I深掘り解説もお楽しみに!
