有人可以向我解释为什么我不能使用%paddr()
BIF将内部过程的地址(存储在字符串变量中)分配给ProcPointer吗?
我的想法是创建一个数字为键的关联数组,并将某个子过程的名称为值。当用户在DSPF中输入数字2时,程序必须调用具有键“ 2”的过程。
据我了解,BIF %paddr()
采用硬编码的过程名称或包含过程名称的字符串。但是,当给一个字符串变量时,编译器会抱怨%PADDR
的参数无效。
答案 0 :(得分:4)
这是因为过程是由编译器静态绑定的。因此,编译器需要在编译时知道要调用什么程序。但是,有些API可在运行时用于绑定服务程序。艾伦·坎宾(Alan Campin)有一些例子here。
让我们再谈谈绑定。调用程序和过程时,IBM i提供两种不同类型的绑定。对于程序,绑定在第一次调用给定程序时在运行时发生,它会解析并绑定到调用方。程序名称可以保存在变量中,并且由于该程序是在运行时绑定的,因此首次通过变量调用该程序时,它将被解析并绑定到调用方,此后,当变量中的值更改时,该程序在下一次调用时再次解析。这称为动态绑定。绑定发生在运行时,可能在每次调用程序时发生,并且在调用者或激活组结束时,绑定会丢失。
过程在编译期间是静态绑定的。过程或过程指针没有内置的运行时绑定。您可以通过使用过程指针来近似动态绑定,但是在内部将过程绑定到过程指针,并且如果通过%paddr()为过程指针提供地址,则绑定将在该点进行。甚至使用回调的API都是静态绑定的。 API绑定到过程指针,调用者将过程指针绑定到回调过程本身,然后将绑定传递给API。在运行时没有解决方案发生。您可以使用此简单程序进行测试。
**free
ctl-opt dftactgrp(*no) actgrp(*new) BndDir('mybnddir');
dcl-s procPtr Pointer(*proc);
dcl-pr proc ExtProc(procPtr);
end-pr;
procPtr = %paddr('MissingProcedure');
proc();
return;
程序无法编译。它在绑定步骤中失败,因为找不到MissingProcedure
。期望接收回调作为参数的API,但是即使不知道回调是什么或回调是否存在也能够编译,因为它仅绑定到程序内部已经存在的过程指针本身。
因此,RPG不提供任何工具来在运行时动态地绑定过程,但是IBM i确实提供了系统API,我们可以使用它们来手动解析服务程序中的过程。这就是我上面提到的Alan Campin的例子。因此,从技术上讲,是的,我们可以动态绑定到服务程序中的过程,但是RPG不提供这样做的便利。那只会在编译时发生。
答案 1 :(得分:2)
%paddr的参数名称必须是常量,正如Charles和Mark所说的那样。
最简单的方法是创建一个过程指针数组。
这里有个例子:
**FREE
ctl-opt main(main) dftactgrp(*no) actgrp(*caller);
dcl-c UPPER 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
dcl-c LOWER 'abcdefghijklmnopqrstuvwxyz';
dcl-proc main;
dcl-pi *n;
index char(1) const;
end-pi;
dcl-s line char(50);
dcl-s procedureName char(256);
dcl-s transformPtr pointer(*proc);
dcl-pr transform char(50) extproc(transformPtr);
input char(50) const;
end-pr;
dcl-s procedures pointer(*proc) dim(2);
procedures(1) = %paddr('TOLOWER');
procedures(2) = %paddr('TOUPPER');
transformPtr = procedures(%int(index));
line = 'Hello, world. =)';
line = transform(line);
dsply line;
end-proc;
dcl-proc toUpper;
dcl-pi *n char(50);
input char(50) const;
end-pi;
return %xlate(UPPER : LOWER : input);
end-proc;
dcl-proc toLower;
dcl-pi *n char(50);
input char(50) const;
end-pi;
return %xlate(LOWER : UPPER : input);
end-proc;