CL

162. *BYVREF と *BYVAL と、どうちがうの?

CLPでプロシージャーを呼び出すとき
CALLPRCコマンドでプロシージャーに渡すパラメータの指定で
 

*BYREF と *BYVAL

_

の2つの種類があるがどうちがうのだろう?
またどのように使い分ければよいのだろう。
よく混同ちがちになるのだが

*BYREF : 変数のポインタをプロシージャーに渡す。

*BYVAL : 変数の値をプロシージャに渡す

のちがいがある。
「ポインタをパラメータとして渡したことなんかない」
と言われるかも知れないがあなたは毎日のようにRPGやCOBOLのプログラムに
ポインタでCLPからRPGヘパラメータを渡すCLPを書いているはずである。

何故ならCLPからRPGへパラメータを渡した後で受けたRPGがそのパラメータの変数を
更新して元のCLPに戻したとするとどうなるか?

–>それは当然CLPに変更した値が戻ってくるに違いない、ということになるが
これはCLPからRPGへ渡すパラメータがポインタとして渡されているからである。
値として渡されたのであればCLPが使っている変数のメモリ域とRPGが使っている同じ名前の変数であってもRPGが使っている変数のメモリ域は異なるので、いくらRPGが変数値を変更したとしても
元のCLPに戻ればCLPで定義されている変数は名前が同じであっても別のメモリに
保管されているのでCLP上での変数値は変わることはない。
つまりRPGでいくら変数の値を更新したとしてもCLPに戻ればその変更は更新されることはない。

これに対してポインタ渡しであればIBM i全体のメモリ上での同じメモリ域で定義された変数として
CLPとRPGでも同じものである。つまりポインタというのはコンピュータ内であらゆるプログラムに
共通して使える絶対的なメモリの場所を示しているので受取ったRPG側でそのポインタを基底とする
変数の値を変更してCLPに戻せばCLPでも同じメモリ域の場所の変数を参照することになるので
結果的に更新された値を受取ることができるのである。

■ CLPの変数名を &で表すのはなぜ?

IBM i のCLPの変数名はご存知のように &NAME , &VALUE, …のように先頭に文字 & を付加して
表現するがこれは C言語では変数のポインタ値を表すことと同じである。
C言語では変数 : STRING のポインタは &STRING のようにして記述する。
CLPで変数を & を付加して表しているのは偶然ではないと思われる。
つまりCLPの変数は基本的にポインタであるように思える。

■ 道路拡張の例

 _

本町という名前の住所はどこの都道府県にも数多くある。
ある県の本町の道路を拡張したとしても別の県の本町の道路が拡張されたわけではない。
しかし東経xx度、北緯yy度という絶対値を指定してその場所の道路をある県が拡張したとしたら
それは別の県から見ても同じ場所の道路が拡張されたことになる。

いわばこのような例と同じである。

■ *BYREF と *BYVAL の使い分け

*BYREF と *BYVAL の話に戻って考えてみると
*BYREF はポインタを示し、*BYVALは値を示すということであった。

こでプロシージャー呼出しでは
バラメータとして

*BYREF : 変数のポインタを渡す
*BYREF : 変数値そのものを渡す

と理解しておけばよい。
_

従って APIを呼び出すときにそのAPIの

[例]

system 関数の呼出し

             DCL        VAR(&CMD) TYPE(*CHAR) LEN(128)
             DCL        VAR(&RES) TYPE(*INT) LEN(4)   
             :
 CALLPRC    PRC('system') PARM((&CMD)) RTNVAL(&RES)

[解説]

system関数のパラメータは Char* としてポインタとして定義されているので
省略時の値として *BYREFでポインタ渡しで呼び出している。

[例]

malloc 関数の呼出し

        DCL        VAR(&RCVBUF) TYPE(*PTR) ADDRESS(*NULL)
              DCL        VAR(&RCVLEN) TYPE(*CHAR) LEN(4) +     
                               VALUE(X'0001F400')                  
              DCL        VAR(&RCVINT) TYPE(*INT) VALUE(128000)  
               :
 CALLPRC    PRC('malloc') PARM((&RCVINT *BYVAL)) +
             RTNVAL(&RCVBUF)     

[解説]

mallocに渡すパラメータは INT (=整数)として定義されているので
整数: RCVLEN (=128000)をそのまま変数値として *BYVAL で渡している。