对于刚刚接触ILE模式开发的初级菜鸟而言,想要搞清楚这三者的区别还是有点难度的。网上虽然一些帖子对这三者进行了比较,但是这些帖子或是语焉不详,或是高度概括。对于老鸟来说或许已经足矣,但是对于初级菜鸟而言,还是理解起来并不容易。下面就由我这个中级菜鸟结合red
book和自己的理解,从一个菜鸟的视角,来尽量的把这三者的区别描述清楚。
前提:你已对这三者有些初步的了解。
一 基本概念
1 CALL是动态调用*PGM类型的OPM或者ILE 程序。(即可执行的程序,区别于*MODULE)。
2 CALLB是静态调用module中的main
procedure(PEP)。(其实CALLB也可以调用subprocedure,但是不推荐这么用,好像也没人这么用。因为既然已经用定义原型的方式定义了subprocedure,为什么不使用CALLP呢?CALLP比CALLB有更多优势)。
所以CALLB一般用来调用没有事先用原型定义声明的main procedure。(因为main procedure不需要定义原型也能用,subprocedure必须定义原型才能使用。如果mian
procedure也定义原型了,那么也用CALLP吧)
3 CALLP 是原型调用方式。顾名思义,使用CALLP必须要定义原型(prototyped),前两者则不用定义原型 。CALLP既可以像CALL那样用动态方式调用OPM或者ILE程序,也可以像CALLB那样静态的调用procedure。CALLP有很多优势,其中很重要的一点是他会在编译期提供参数检查(parameter
checking),这样会避免一些运行期(run-time)的错误。
二 调用范围:
CALL:OPM 或者ILE program。(前提:调用的PGM要在当前LIB
LIST中存在)
CALLB/CALLP: (前提:调用的procedure要在bind directory中有定义)
1同一个ILE program中的procedure。
2同一个ILEprogram中,相同的service program中的procedure
3同一个ILE program中,不同的service program中的procedure。
三 如何选择三者?
CALL和CALLB能实现的功能,CALLP都可以实现,并且CALLP还提供了参数检查,by
value ,by read-only reference的传参方式等优势,并且定义个原型也并不是很困难的事,所以尽量使用CALLP。
四 效率
这个地球人都知道,静态调用肯定比动态调用效率高,但是高多少,我没测试过,不清楚。
补充:什么是动态调用,静态调用,编译期参数检查?
1 假设:PGMA调用PGMB
动态调用:PGMA不知道PGMB在系统中的哪个位置,PGMA在调用PGMB的时候(run-time),按照当前的library
list依次来寻找PGMB,这就是动态调用。
2 假设:PGM1 中的PROCA 调用PROCB
静态调用:PGM1 在编译的时候,编译器就把PROCB的地址信息保存在PGM1中了(具体binding的方式有by
copy 和by reference两种)。当PROCA调用PROCB的时候,PROCA根据PROCB的地址,能够直接找到PROCB的位置,而不用像动态调用那样,要按照library
list挨个library来搜索。这种方式就是静态调用。
3 编译期参数检查
Compile-time parameter checking是指在编译的时候,编译器会检查你传给procedure的参数是否和prototype里定义的一样。包括参数类型,以及是否有可忽略的参数等。不一样的话编译会报错,无法通过。能够减少运行期的错误。
假设PGMA 调用PGMB,PGMB 有2个入口参数,如下所示:
*ENTRY PLIST
PARM P1 5P 0
PARM P2 5A
如果不用原型定义的话,那么PGMA调用PGMB的时候,传给PGMB2个参数,分别是10P
0和6A,即
CALL PGMB
PARM A1 10P 0
PARM A2 6A
这样的话,PGMA是可以通过编译的,但是实际调用的时候,有可能造成数据异常,或者程序异常。
如果使用原型定义的话:
D pgmbb PR EXTPGM(‘PGMB’)
D 5P 0
D 5A
那么当PGMA再次传给PGMB 10P 0 和 10A的参数时,编译就会报错,无法通过, 减少运行期的错误。
CALLP pgmbb(A1,A2) /*编译无法通过