メニューボタン
IBMi海外記事2018.12.13

%PARMSでCLに関する2つの問題を解決する

Ted Holt 著

IBMの優秀なスタッフたちが、また素晴らしい仕事をしてくれました。2つの問題を解決する新たなCL機能を追加してくれたおかげで、私はもうそれらの問題の対処に悩む必要がなくなりました。この記事では、新たな%PARMS組み込み関数について紹介します。

%PARMS関数は、CLプロシージャー(すなわちCLプログラムまたはCLモジュール)に渡されるパラメーターの数を返します。以前は、私はメッセージMCH3061を監視していました。そうすることで問題が何も生じないケースもありますが、すべてのケースでうまく行くわけではありません。%PARMS関数は、パラメーターが渡されたかどうかを知る明確な方法を提供してくれます。IBMは、PTF SI66721でIBM i 7.3向けに%PARMSをリリースしています。

以下では、2つの問題を取り上げて、%PARMSを使ってそれらの問題を防止する方法について説明します。

プログラムの問題

次のPARMTESTというプログラムについて検討してみましょう。

pgm (&p1 &p2 &p3)

   dcl &p1     *char    3
   dcl &p2     *char    3
   dcl &p3     *char    3

   dcl &msg    *char   14

   ChgVar  &msg  ('/' *cat &p1 *cat ' ' *cat +
                           &p2 *cat ' ' *cat +
                           &p3 *cat '/')

   SndPgmMsg  msg(&msg) MsgType(*comp)

3つのパラメーターを渡してこのプログラムを呼び出すと、渡した値を含んだメッセージが表示されます。

call PARMTEST (AAA BBB CCC)
/AAA BBB CCC/

しかし、渡したパラメーターが3つに満たない場合は、別の表示になります。

call PARMTEST (AAA BBB)
MCH3601	Pointer not set for location referenced.
CPF9999	Function check. MCH3601 unmonitored by PARMTEST at statement 0000000900, 
instruction X'0000'.
CPA0702 MCH3601 received by procedure PARMTEST. (C D I R)

CHGVARコマンドがキャンセルされました。これは1つパラメーター値が与えられなかったためです。%PARMSを使用してこの問題を回避する方法を以下に示します。

pgm (&p1 &p2 &p3)

   dcl &p1     *char    3
   dcl &p2     *char    3
   dcl &p3     *char    3

   dcl &x1     *char    3   value('DFT')
   dcl &x2     *char    3   value('DFT')
   dcl &x3     *char    3   value('DFT')

   dcl &msg    *char   14

   if (%parms *ge 1) then(ChgVar &x1 &p1)
   if (%parms *ge 2) then(ChgVar &x2 &p2)
   if (%parms *ge 3) then(ChgVar &x3 &p3)

   ChgVar  &msg  ('/' *cat &x1 *cat ' ' *cat +
                           &x2 *cat ' ' *cat +
                           &x3 *cat '/')
   SndPgmMsg  msg(&msg) MsgType(*comp)

コードを書き直して、CHGVARコマンドがパラメーター変数を参照するのではなく、ローカル変数を参照するようにしました。パラメーターからローカル変数をロードしますが、それは、それらのパラメーターがプログラムに渡された場合だけです。それ以外の場合、ローカル変数はデフォルト値になります。

call PARMTEST (AAA BBB CCC)
/AAA BBB CCC/
call PARMTEST (AAA BBB)
/AAA BBB DFT/
call PARMTEST (AAA)
/AAA DFT DFT/
call PARMTEST
/DFT DFT DFT/

1つ目の問題は解決しました。今度は2つ目の問題を見てみましょう。

モジュールの問題

同じコードを検討しますが、今度はPARMTESTがプログラムではなく、モジュールとしてコンパイルされます。以下は、モジュールCALLERのソースコードです。これはモジュールPARMTESTを呼び出します。

pgm

   CallPrc  PARMTEST  (AAA BBB CCC)
   CallPrc  PARMTEST  (DDD EEE)
   CallPrc  PARMTEST  (FFF)
   CallPrc  PARMTEST

endpgm

CRTCLMOD(Create CL Module:CLモジュールの作成)コマンド(PDMのオプション15)を使用して両モジュールを作成し、CRTPGMを使用してそれらを1つのプログラムにバインドします。

CRTCLMOD MODULE(MYLIB/PARMTEST) +
   SRCFILE(QCLSRC) SRCMBR(PARMTEST)
CRTCLMOD MODULE(MYLIB/CALLER) +
   SRCFILE(QCLSRC) SRCMBR(CALLER)
CRTPGM PGM(CALLER) MODULE(CALLER PARMTEST) +
   ACTGRP(*NEW)

これでプログラムが作成されました。このプログラムを呼び出すと、結果は以下のようになります。

CALL CALLER
/AAA BBB CCC/
/DDD EEE CCC/
/FFF EEE CCC/
/FFF EEE CCC/

3つのパラメーターをすべて渡していなくても、CALLERは、3つすべてが渡されたとみなします。パラメーターを渡さないと、CALLERは以前の呼び出しのデータを使用します。そのデータへのポインターがたまたまメモリー内に残っているためです。これでは、誤った、予測できない、好ましくない結果が生じる可能性があります。

けれども、代わりに新バージョンのPARMTESTモジュールを使用すれば、以下のようになります。

CALL CALLER
/AAA BBB CCC/ 
/DDD EEE DFT/ 
/FFF DFT DFT/ 
/DFT DFT DFT/

%PARMSのおかげで、渡されていないパラメーターに対してデフォルト値を使用することができました。

MCH3601を監視する必要はあるでしょうか。さあどうでしょう。私がそうすることは、たぶんないでしょう。

あわせて読みたい記事

PAGE TOP