第8章  サブルーチン
RPGプログラマーの為のC言語講座

サブルーチンの使い方

サブルーチンの使い方についてRPGとCを比較して見ましょう!

RPGでのサブルーチンの使用法は以下の通りです。


     H            Y/                                    1
     H*---------------------------------------------------------------*
     H* PROGRAM-ID    :    CSPEC1R                                    *
     H* REMARKS       :    サブルーチン                               *
     H* AUTHOR        :    Y.IDE                                      *
     H* DATE-WRITEN   :    1999/10/30                                 *
     H* VERSION       :    01.00 ORIGINAL                             *
     H*---------------------------------------------------------------*
     C* メインルーチン
     C                     EXSR SUB#R1
     C                     EXSR SUB#R2
     C                     SETON                     LR
     C                     RETRN
     C* サブルーチン
     C*------------------------------------------------*
     C           SUB#R1    BEGSR
     C*------------------------------------------------*
     C           'SUB#R1'  DSPLY
     C                     ENDSR
     C*------------------------------------------------*
     C           SUB#R2    BEGSR
     C*------------------------------------------------*
     C           'SUB#R2'  DSPLY
     C                     ENDSR

    			EXSR サブルーチン名
    
    サブルーチン名 	BEGSR
    
    			ENDSR
    
    

サブルーチンの呼出しは EXSR で行いサブルーチンのコードは、
BEGSR 〜 ENDSR の間に記述し、メインルーチンの後ろにおきます。

Cのサブルーチンの使用法は以下の通りです。


/*---------------------------------------------------------------*/
/* PROGRAM-ID  : CSPEC1                                          */
/* REMARKS     : C仕様書サブルーチン                            */
/* AUTHOR      : Y.Ide                                           */
/* DATE-WRITEN : 1999/10/30                                      */
/* VERSION     : 01.00 ORIGINAL                                  */
/*---------------------------------------------------------------*/

#include<stdio.h>
#include<stdlib.h>

/* サブルーチン */
void sub_r1(void){
  printf(" サブルーチン1 ??/n");
  return;
}

/* プロトタイプ */
void sub_r2(void);

/* メインルーチン */
int main(int argc, char *argv[]){
  sub_r1();
  sub_r2();
  exit(0);
}

/* サブルーチン (mainの後ならプロトタイプが必要) */
/*----------------------------------------*/
  void sub_r2(void){
/*----------------------------------------*/
    printf(" サブルーチン2 ??/n");
    return;
  }

サブルーチンの呼出しは ルーチン名(Cでは通常サブルーチンとは言わず関数と呼びます)で行い サブルーチンのコードは、{ }の間に記述し、メインルーチンの前におきます。

メインルーチンの後ろに置く場合は(上記 sub_r2 )は、関数の戻り値と引数だけ記述した、 プロトタイプをメインルーチンの前におきます。
プロトタイプがない場合は、コンパイルのときに警告メッセージがでます。

また、RPGの場合は、サブルーチンは必ず同じコードないに記述し、同時にコンパイルすることが必要ですが、 ILEでは、モジュール別に分割して作成することが可能です。

上記の例では、

/* サブルーチン (mainの後ならプロトタイプが必要) */
/*----------------------------------------*/
  void sub_r2(void){
/*----------------------------------------*/
    printf(" サブルーチン2 ??/n");
    return;
  }
の部分は、別のモジュールとして作成し、後からバインドすることが可能です。

また、上記のプログラムでは、void sub_r2(void) となっていますが、void というは、 型を持たないということを示します。
つまり、上記は、このサブルーチン(関数)には、引数として渡すパラメータも、戻り値として帰される値もないことを 表しています。

ですから、呼出す場合は、

    sub_r2();
となります。

もし、int sub_r2(void) となっていた場合には、その呼び出しは、

    rc = sub_r2();
となるでしょう。(rc は省略しても構いません)

もし、void sub_r2(int) となっていた場合には、その呼び出しは、

    sub_r2(rc);
となるでしょう。この場合の rc は必須です。
注意が必要なのは、Cの引数は値渡しなので、rc はサブルーチンには渡りますが、呼出しもとのプログラムに は戻ってきません。
このことは、もしサブルーチン内部で、rc の値を変更したとしても、呼出しもとの rc の値には影響がない(変更が反映しない)ことを意味します。

もし、サブルーチンの変更結果を戻す必要があるのなら、戻り値とする、or 引数をポインターとして定義する or フィールドの有効範囲(スコープ)を main の外側に出す、ことが必要です。

  1. 戻り値とする。以下のように記述します。
    int main(int argc, char *argv[]){
      int rc;
      rc = sub_r2();
    }
    /*----------------------------------------*/
      int  sub_r2(void){
    /*----------------------------------------*/
        int rc;
    	rc = 1;
        return rc;
      }
    
  2. 引数をポインターとして定義する
    int main(int argc, char *argv[]){
      int rc;
      sub_r2(&rc);
    }
    /*----------------------------------------*/
      void  sub_r2(int *rc_ptr){
    /*----------------------------------------*/
    	*rc_ptr = 1;
        return;
      }
    
    ポインターをパラメータとして渡しているので、サブルーチンが変更するのは、main ルーチンのフィールドとなる。

    つまり、サブルーチンでの変更が反映することになります。

  3. フィールドの有効範囲(スコープ)を main の外側に出す
    (注)Cでのフィールドは、定義された{}の中でだけで有効です。
    {}の外側で定義するとプログラム全体で有効となります。
    int rc;
    
    int main(int argc, char *argv[]){
      sub_r2();
    }
    /*----------------------------------------*/
      void  sub_r2(void){
    /*----------------------------------------*/
    	rc = 1;
        return;
      }
    
    この例では、rcは main の外側で定義されています、この場合、rc の有効範囲は以降全てのルーチン(関数)に 及びます。

    つまり、変更が反映することになります。

    OPM−RPGには、内部サブルーチンにパラメーターを渡すことができません。

    OPM−RPGには、フィールドの有効範囲がありません。

    RPGでのフィールド定義は、プログラムのすべてのルーチンで有効です。

    つまり、この例が、OPM−RPGのサブルーチン呼出しに一番近い呼出し方法となります。