【実務・中級編】LENGTHおよびCURRENTSIZEビルトイン関数の違い – PL/Iの基本構文とデータ制御実践ガイド

こんにちは、若手エンジニアの皆さん。日々のメインフレーム保守、本当にお疲れ様です。深夜のバッチ窓口対応や、山のようなVSAMファイルのダンプ解析に追われていないでしょうか。

さて、私たちが日常的に向き合っているPL/I(Programming Language One)。COBOLに比べると圧倒的な表現力を誇り、ポインタ操作から複雑な構造体制御までこなせる素晴らしい言語ですが、その自由度の高さゆえに、言語仕様の微妙な勘違いが原因で本番障害を引き起こすケースが後を絶ちません。

今回は、数々の大規模バッチ改修やオープン系へのマイグレーション現場で、私が幾度となく後輩のコードレビューで指摘してきた「LENGTH」と「CURRENTSIZE」ビルトイン関数の違いについて、徹底的に解説します。

文字数やサイズを扱う処理で、この2つを取り違えると、レコード入出力時にバッファオーバーランを起こしたり、VSAMファイルの可変長レコードが途中で切れてサイレントエラーになったりします。今日の話を頭に叩き込んでおけば、もう夜間バッチで冷や汗をかくことはなくなるはずです。さあ、いってみましょう。

—

1. なぜこの違いが現場のエンジニアを悩ませるのか?

PL/Iの最大の特徴の一つに「キーワード(予約語)の文脈依存性」があります。COBOLであれば `RESERVED WORD` の長大なリストがありますが、PL/Iには原則として「真の予約語」というものが存在しません。`IF` や `LENGTH` さえも、プログラマが変数名として定義してしまえば、コンパイラは文脈からそれを判断します(もちろん、そんな恐ろしいコーディングをする人はいませんが)。

そんな柔軟なPL/Iにおいて、データの「大きさ」を取得したいときによく使われるのが `LENGTH` と `CURRENTSIZE`(あるいは `SIZE`)です。

文字通り「長さ」を意味する英語ですが、メインフレームの世界では「論理的な文字数・要素数」と「物理的なメモリ占有バイト数」は全く別物です。ここを混同することが、レガシーシステムのバグの温床となっています。

—

2. LENGTH関数:文字列の「論理長」を捉える

基本仕様と挙動

`LENGTH` ビルトイン関数は、主に文字ストリング(CHARACTER型)の現在の文字数(長さ)を取得するために使用します。

ここで重要なのが、PL/Iの文字列型には大きく分けて以下の2つがある点です。
1. VARYING属性なし(固定長): `CHAR(10)` のように宣言されたものは、実際に中に何が入っていようと、`LENGTH` は常に宣言された最大長(この場合は10)を返します。
2. VARYING属性あり(可変長): `CHAR(10) VARYING` のように宣言されたものは、文字列の実データが変化します。例えば “IBM” という3文字が入っていれば、`LENGTH` は `3` を返します。

実務での罠:VSAM可変長レコードとの絡み

可変長レコード(VB形式など)を扱う際、レコード長を計算するために安易に `LENGTH(RECORD_AREA)` を使うと痛い目を見ます。VARYINGではない通常の固定長領域に対して `LENGTH` を呼ぶと、常に最大長が返されるため、実際の有効データ長とは乖離してしまいます。

—

3. CURRENTSIZE関数:メモリ上の「物理占有バイト数」を捉える

基本仕様と挙動

一方、`CURRENTSIZE`(または単に `SIZE`)ビルトイン関数は、変数や構造体がメインメモリ(またはレコードバッファ)上で実際に占有している物理的なバイト数を返します。

構造体(STRUCTURE)や、様々なデータ型が混在するエリアのサイズを知りたいときには、こちらの独壇場です。例えば、ポインタが指し示している基底変数(BASED変数)や、ロケーターを用いた動的領域の大きさを確認する際には、`CURRENTSIZE` が不可欠となります。

—

4. 【実践】コードで違いを体感するPL/Iプログラム

百聞は一見にしかず。実際のメインフレームのバッチジョブを想定したPL/Iのサンプルコードを見てみましょう。大文字ベースで記述し、実務でそのまま使えるコメントを付与しています。

—————————————————————-

  • プログラム名: SIZETEST
  • 概要 : LENGTHとCURRENTSIZEの挙動比較実習プログラム

—————————————————————-
SIZETEST: PROC OPTIONS(MAIN);

DCL 1 W_KOTEI_REC,
3 W_ID CHAR(5),
3 W_DATA CHAR(20);

DCL 1 W_KAEHEN_REC BASED(P_REC),
3 W_K_LEN FIXED BIN(15),
3 W_K_BODY CHAR(100) VARYING;

DCL W_STR_FIX CHAR(30) INIT(‘IBM_MAINFRAME’);
DCL W_STR_VAR CHAR(30) VARYING INIT(‘PL/I_LANGUAGE’);

DCL P_REC POINTER;
DCL W_LEN_VAL FIXED BIN(31);
DCL W_SIZ_VAL FIXED BIN(31);

PUT SKIP LIST(‘=== 1. 文字列変数の比較 ===’);

/ 固定長文字列に対するLENGTHとCURRENTSIZE /
W_LEN_VAL = LENGTH(W_STR_FIX);
W_SIZ_VAL = CURRENTSIZE(W_STR_FIX);
PUT SKIP EDIT (‘FIXED CHAR LENGTH : ‘, W_LEN_VAL) (A, F(5));
PUT SKIP EDIT (‘FIXED CHAR CURRENTSIZE: ‘, W_SIZ_VAL) (A, F(5));
/ 解説: どちらもCHAR(30)なので、論理長も物理サイズも30バイト /

/ 可変長文字列に対するLENGTHとCURRENTSIZE /
W_LEN_VAL = LENGTH(W_STR_VAR);
W_SIZ_VAL = CURRENTSIZE(W_STR_VAR);
PUT SKIP EDIT (‘VARYING CHAR LENGTH : ‘, W_LEN_VAL) (A, F(5));
PUT SKIP EDIT (‘VARYING CHAR CURRENTSIZE: ‘, W_SIZ_VAL) (A, F(5));
/ 解説: LENGTHは現在の実文字数(“PL/I_LANGUAGE” = 13)を返し、
CURRENTSIZEはVARYINGの管理領域(2バイトのプレフィックス)
を含む最大確保サイズ分を返すため注意が必要 /

PUT SKIP LIST(‘=== 2. 構造体(レコード)の比較 ===’);

W_LEN_VAL = LENGTH(W_KOTEI_REC);
W_SIZ_VAL = CURRENTSIZE(W_KOTEI_REC);
PUT SKIP EDIT (‘STRUCT FIXED LENGTH : ‘, W_LEN_VAL) (A, F(5));
PUT SKIP EDIT (‘STRUCT FIXED CURRENTSIZE: ‘, W_SIZ_VAL) (A, F(5));
/ 解説: 固定長構造体では基本的に一致するが、
コンパイラの境界整列(ALIGNMENT)規則により
CURRENTSIZEの方がパディングを含んで大きくなる場合がある /

RETURN;
END SIZETEST;

—

5. 現場のシニアが教えるトラブルシューティングとコーディング標準

最後に、私たちが実務の現場で胸に刻むべき「使い分けの鉄則」をまとめます。

1. 画面入出力やテキスト処理には `LENGTH` を使え
文字列の切り出し(SUBSTR)の終端や、文字データの有効長を判定するロジックでは、常に `LENGTH`(特にVARYING変数に対して)を使用してください。
2. VSAMのWRITE/REWRITE文、またはストレージ管理には `CURRENTSIZE` を使え
VSAMやQSAMへレコードを出力する際、物理的なレコード長を指定する場面では `CURRENTSIZE`(あるいは `SIZE`)を使用するのが鉄則です。ここで `LENGTH` を誤用すると、可変長レコードの末尾が欠損したままディスクに書き込まれ、後続のジョブでABEND(S0C4やデータ例外)を引き起こす主原因となります。
3. アライメント(境界整列)の罠を忘れるな
メインフレームのハードウェア特性上、半ワード境界、フルワード境界にデータを配置する方がアクセス効率が良いため、コンパイラが勝手にパディング(隙間)を挿入します(`ALIGN` 属性)。構造体全体の物理サイズを正確に取得したい場合は、`LENGTH` ではなく必ず `CURRENTSIZE` を選択してください。

レガシーシステムの寿命は私たちが想像しているよりも長く、そして私たちが書く1行のコードの重みは計り知れません。言語仕様の裏側にある「メモリの動き」まで想像力を働かせることこそが、真のメインフレームアーキテクトへの第一歩です。

今回の解説が、皆さんの日々の開発・保守業務の助けになれば幸いです。それでは、次回のトラブルシューティングでお会いしましょう。

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