ポインタの「魔物」を飼い慣らせ:PL/IにおけるNULL関数の正しい作法
やあ。今日も今日とて、JCLのジョブカードと格闘しているか?
メインフレームの世界で長く生き残っていると、C言語やJavaから入ってきたエンジニアが、PL/Iのポインタ操作で盛大に足元をすくわれる場面に何度も出くわす。特に、ポインタの初期化やNULL比較の甘さは、バッチ処理の深夜の異常終了(ABEND)を招く最大の戦犯だ。
今日は、PL/Iにおける`NULL`ビルトイン関数と、ポインタを安全に扱うための「作法」について、現場の知見を交えて語ろうと思う。
—
なぜポインタの初期化を怠ってはいけないのか
PL/Iにおいて、ポインタ変数を宣言しただけでは、その中身は「ゴミ(未定義値)」だ。C言語ならセグメンテーションフォールトで即死するような場面でも、メインフレームのPL/Iは空気を読んで(あるいは無視して)動こうとする。その結果、本来指すべきではない謎のアドレスを参照し、データセットを破壊したり、意味不明な値を計算に使ったりする。
`NULL`ビルトイン関数は、そのポインタが「どこも指していない」ことを明示する、いわば防波堤だ。
実践的なコーディング・パターン
まずは、基本的な作法を見てくれ。VSAMファイルを読み込み、動的にメモリを確保してデータを加工するような、バッチ処理の典型的なパターンだ。
/i
/——————————————————————-/
/ プログラム名: SAMPLE01 /
/ 機能: VSAMレコードの動的領域への読み込みとNULLチェック /
/——————————————————————-/
SAMPLE01: PROCEDURE OPTIONS(MAIN);
/ ポインタ変数の宣言 /
DCL P_REC_AREA POINTER INITIAL(NULL()); / 必ずNULLで初期化する /
/ 領域のベースとなる構造体 /
DCL 1 REC_STRUC BASED(P_REC_AREA),
5 KEY_FLD CHAR(8),
5 DATA_FLD CHAR(100);
/ VSAMアクセス用ファイルの宣言 /
DCL VSAM_FILE FILE RECORD INPUT;
/ エラーハンドリング(ONユニット) /
ON ENDFILE(VSAM_FILE) BEGIN;
/ ここでポインタの解放を行うのが定石 /
IF P_REC_AREA ^= NULL() THEN DO;
FREE REC_STRUC;
P_REC_AREA = NULL(); / 解放後は必ずNULLに戻す /
END;
END;
/ 処理開始 /
OPEN FILE(VSAM_FILE);
/ 動的メモリ確保とNULLチェック /
ALLOCATE REC_STRUC;
IF P_REC_AREA = NULL() THEN DO;
PUT SKIP LIST(‘メモリ確保に失敗しました’);
SIGNAL ERROR;
END;
/ …ここにVSAM読み込みや加工処理が入る… /
CLOSE FILE(VSAM_FILE);
END SAMPLE01;
—
現場で「唸る」ための3つの鉄則
コードを見れば分かる通り、単に`NULL()`を使うだけでは不十分だ。以下のポイントを徹底してくれ。
1. 解放(FREE)後の再NULL化
意外と多いのが、`FREE`した後にポインタ変数をそのまま放置するケースだ。`FREE`を実行しても、ポインタ変数の値が自動的に`NULL`になるわけではない。いわゆる「ダングリングポインタ(浮遊ポインタ)」状態だ。必ず`P_REC_AREA = NULL();`とセットで記述する癖をつけろ。
2. 比較演算子 `^= NULL()` の徹底
ポインタが有効かどうかをチェックする際、`IF P_REC_AREA = ADDR(SOME_DATA)`のように書くこともあるが、基本は`NULL()`との比較だ。特にVSAMの戻り値判定や、チェーンリストの末尾判定には、必ずこの`NULL`チェックを挟むこと。これをサボったせいで、S0C4エラー(記憶保護例外)に泣かされるのは、この業界の通過儀礼とはいえ、避けられる災難だ。
3. ONユニット内での安全策
大きなバッチ処理では、異常終了時の後始末をONユニットに書くことが多い。ここでポインタが初期化されていないと、エラー処理の最中にさらにエラー(ダブルフォルト)が発生する。ONユニット内でのポインタ参照は、常に`NULL`チェックを先行させるのが、熟練のやり方だ。
—
最後に:ポインタは「信頼」ではなく「確認」
ポインタは、メモリを直接操る強力なツールだ。しかし、強力であるがゆえに、一度でも制御を失えば、システム全体を巻き込むバグの温床となる。
「自分が初期化したはずだ」「さっき確保したばかりだから大丈夫」……そう思った瞬間が、一番危ない。PL/Iコンパイラは、コードを厳格に解釈する。君もまた、ポインタに対して厳格であり続けてほしい。
もし、レガシーコードのメンテナンスで「なぜか値が化ける」「原因不明のS0C4が出る」という案件に当たったら、まずはそのポインタが生成された瞬間から、最後まで`NULL`が正しく管理されているか、トレースしてみるといい。大抵の答えは、そこにあるはずだ。
それじゃあ、健闘を祈る。また何かあったら聞きに来い。
