1. 導入:なぜこの指定が必要なのか
メインフレームでPL/IからC言語やアセンブラなどの他言語を呼び出す際、最も頻繁に発生するのが「文字列の長さが正しく伝わらない」「メモリの解釈がずれる」という不具合です。PL/Iは標準で文字列の長さやメモリ境界情報を「記述子(Descriptor)」として引数に付加しますが、他言語側はこれを予期していません。この挙動を制御するDESCRIPTORS / NODESCRIPTORSを理解することは、システム間連携の堅牢性を高めるために不可欠です。
2. 基礎知識:記述子(Descriptor)とは何か
PL/Iの文字列(CHARACTER)を引数として渡す際、PL/Iは単にデータ本体のアドレスを渡すだけでなく、その文字列の長さなどの情報を含めた「制御ブロック(記述子)」を裏側で渡しています。
・DESCRIPTORS(デフォルト): PL/Iが自動的に記述子を渡します。PL/I同士の呼び出しでは便利ですが、C言語側にはこの情報は「余計なゴミ」として映ります。
・NODESCRIPTORS: 記述子を渡さず、データ本体のアドレスのみを渡します。C言語の `char` と直接マッピングさせる場合に必須の指定です。
3. 実装と解決策
他言語(特にC言語)を呼び出す際は、ENTRY属性で明示的に `OPTIONS(NODESCRIPTORS)` を指定します。これにより、PL/Iは記述子を生成せず、純粋なポインタのみを渡すようになります。ただし、NODESCRIPTORSを指定した場合、文字列の長さ情報は自動的には渡されなくなるため、別途引数として長さを渡す設計が必要です。
4. サンプルプログラム
以下は、NODESCRIPTORSを指定して外部C関数を呼び出す際のPL/I側の宣言例です。
/ PL/I側:外部ルーチン呼び出しの宣言 /
/ C言語側の関数: void my_c_func(char str, int len); を想定 /
DCL MY_C_FUNC ENTRY(
CHAR() VAR, / 文字列本体 /
FIXED BIN(31) / C側に渡すための明示的な長さ情報 /
) OPTIONS(NODESCRIPTORS);
DCL MY_STRING CHAR(20) INIT(‘Hello Mainframe’);
DCL STR_LEN FIXED BIN(31);
/ 文字列の有効な長さを取得し、明示的に渡す /
STR_LEN = LENGTH(TRIM(MY_STRING));
/ 呼び出し実行 /
CALL MY_C_FUNC(MY_STRING, STR_LEN);
5. 応用・注意点
現場で陥りやすい罠として、「呼び出し先がPL/IかCかによって、ENTRY属性の記述を変え忘れる」というケースがあります。
・デバッグのコツ: 呼び出し先で文字化けや意図しないメモリ破壊が起きる場合、まずこのオプションが正しく設定されているかを確認してください。
・現代言語への移行: JavaやTypeScriptへ移行する際、PL/Iの「記述子付きデータ」はそのままでは扱えません。NODESCRIPTORSを使用してデータを「フラットなバイト配列」として取り出すインターフェースを一度挟むのが、移行時の定石となります。
「暗黙の挙動」を「明示的な制御」に切り替える。これがメインフレーム技術者の腕の見せ所です。ぜひ設計書の見直し時に活用してください。

コメント