CL

83. CALLPROC の *BYVAL パラメータとは ?

OS V5R4M0 からは CALLPROC (プロシージャー呼び出し) のパラメータのキーワードには
パラメータの受け渡し方法が指定できるようになっている。
省略値は *BYREF であるが、 *BYVAL を指定することもできる。
一体、この *BYREF*BYVAL とは何であろうかと疑問に思う諸氏も少なくないと思う。
そこでこの *BYREF*BYVAL の意味と CLP の変数の意味を考えて頂く機会として
解説を行いたい。

【例】
ソースコード
  DCL        VAR(&DATA) TYPE(*CHAR) LEN(1280)
  DCL        VAR(&OPT) TYPE(*CHAR) LEN(4) +   
           VALUE(X'00000001') /* EBCDIC */
   :

  CALLPRC    PRC(RPGSEND) PARM((&DATA *BYREF) (&OPT + 
            *BYVAL) (960)) 

Visual BASIC でも *BYREF*BYVAL の指定があるように、

である。
簡単に言えば、*BYREF はポインター値がパラメータであり、*BYVAL は変数値がパラメータである。
上記の例であれば呼び出されるプロシージャー: RPGSEND は次のように定義されている。

ソースコード
1765.00 /***********************************************/ 
1766.00 int   RPGSEND(char* sndbuf, int opt, int sndlen)  
1767.00 /***********************************************/ 
1768.00 /* opt : 1= EBCDIC, 2= ASCII */                   
1769.00 {                                                 
            :
            :
1818.00     return TRUE;
1819.00 }               

ご覧のように RPGSEND プロシージャーは C言語のソースであり、
第一パラメータは char* sndbuf という文字ポインターである。
第二パラメータは int opt という integer の整数値パラメータである。
従って

CALLPRC    PRC(RPGSEND) PARM((&DATA *BYREF) (&OPT + 
          *BYVAL) (960))

とは第一パラメータは文字ポインターであるため、ポインターを示す *BYREF を使って
記述されているし、第二パラメータは整数値であるため *BYVAL を使って *BYVAL によって
記述されているのである。

ところで CALLPRC コマンドの省略時の値は *BYREF である。
つまりポインター渡しが省略値なのである。
OS V5R4M0 以前は *BYREF/*BYVAL の区別もなかったのであるから、それまでも
*BYREF としてパラメータ値が渡されていたことになる。
RPG 開発者はよもやポインターを渡していたとは思わなかったであろう。
そのまま CLP の変数を渡すことはポインター値を渡していることになっていたのである。

もっと言えば、

CLP から RPG (=ILE-RPGも含む) や COBOL に渡してしたパラメータは
これまで、すべてポインター渡しであった。

ということが言えるのである。

RPG の開発者なら CLP から受取ったパラメータの値を呼び出された側の
RPG のプログラムの中で値を変更して呼び出し側の CLP に戻すと
そのパラメータ値が変更されることは誰でも知っていると思う。
一般に汎用的な関数で値を受け取って、そのパラメータ値を変更して元の
呼び出し側に戻ってもパラメータ値が変更されることは、ない。

RPGでパラメータ値を変更することができるのはポインター渡しで
渡しているからに他ならない。

他の C, Java, BASIC などでこのような例はない。
IBM がパラメータ渡しを基本として RPG を設計したのは、そのほうがIBM ユーザーにとって
わかりやすい、と判断したからであろう。
私たちは知らないうちにポインター渡しを使っていたのである。
ひとつ内部的な理解を頂けたかと思う。