導入
メインフレームでC言語や外部サブルーチンと連携する際、意外な落とし穴となるのが「ヌル終端(Null-terminated)」の扱いです。特に、PL/IやCOBOLといった伝統的な言語とC言語の作法を混在させている環境では、文字列の長さを誤認することでメモリ破壊を引き起こすケースが後を絶ちません。今回は、CHARACTER VARYINGZ型を使用する際に直面する「論理長」と「物理サイズ」の乖離について解説します。
基礎知識
メインフレームの環境において、CHARACTER VARYINGZ型は、C言語の文字列のように末尾に「ヌル文字(x’00’)」を付加してデータの終わりを識別します。
ここで重要なのは、以下の2つの関数の挙動の違いです。
LENGTH関数は、文字列としての「論理的な文字数」を返します(ヌル文字は含まれません)。
STORAGE関数は、その変数がメモリ上で占有している「物理的なバイト数」を返します(ヌル文字分である+1バイトを含みます)。
この「+1の差」を意識せずにメモリ領域を確保したり、転送したりすると、バッファオーバーフローの原因となります。
実装/解決策
C言語のサブルーチンへデータを渡す際は、必ずSTORAGE関数で確保されたサイズを基準にするか、あるいはヌル文字分を考慮したバッファ設計を行う必要があります。特に移行案件では、現代的な言語の String.length() の感覚で実装すると、末尾の1バイトが欠落したり、逆に隣接するメモリ領域を上書きしたりする事故が発生します。
サンプルプログラム
以下は、VARYINGZ型の文字列をC言語ライクな処理に渡す際の、正しいサイズ計算のサンプルコードです。
/ PL/I形式のサンプルコード /
DCL V_STR CHAR(20) VARYINGZ INIT(‘MAINFRAME_DATA’);
DCL LOGICAL_LEN FIXED BIN(31);
DCL PHYSICAL_SIZE FIXED BIN(31);
/ LENGTHはヌルを含まない文字数を返す /
LOGICAL_LEN = LENGTH(V_STR);
/ STORAGEはヌル文字分(1バイト)を含めたサイズを返す /
PHYSICAL_SIZE = STORAGE(V_STR);
/
- 外部ルーチンに渡す際は、物理的なバッファサイズを渡すのが安全です。
- ヌル文字まで含めて転送する必要があるため、STORAGEを使用します。
/
CALL EXTERNAL_SUBROUTINE(ADDR(V_STR), PHYSICAL_SIZE);
/ コメント:バッファ破壊を防ぐため、常に物理サイズを意識すること /
応用・注意点
現場で最も多いバグは、文字列のコピー時に「LENGTH + 1」の計算を忘れてバッファを確保し、最後のヌル文字が書き込めずに処理が暴走するケースです。
また、CHARACTER VARYINGZは、内部的に長さフィールド(2バイト)と実データ、そして終端ヌル文字で構成されています。外部プログラムとインターフェースを取る際は、必ず「長さフィールドを含んでいるのか」「ヌル文字を含んでいるのか」というインターフェース仕様を文書で明確化しておきましょう。特に、古いCのライブラリは、文字数ではなく「ヌル終端を含めたバイト数」を引数に要求することが多いため、常にSTORAGE関数を基準に設計することをお勧めします。

コメント