Back to Tylogix Home Page

Using C Functions in ILE RPG

By Thibault Dambrine

Every once in a while, you get an assignment that forces you to explore new horizons.

Recently, this happened to me. In the process, I have learned more than I expected about the abilities of the AS/400 to mix and match language functions.

Here is the story: I was assigned a deceptively simple task to accomplish. I had to come up with a random number generator that would be used simultaneously by a large number of on-line users and possibly batch processes. Looking for the most economical solution first, (why re-invent the wheel?) I first dug up a time-based routine from TAATOOL. Under light loads, it worked fine. However, when bombarded with numerous requests in a short period of time, I found that too many of the random numbers generated were the same. This was not acceptable.

Being a proud RPG programmer, I then tried to code my own time-based routine in RPG, using one thousandths of a second as a seed. Again, under light loads, it worked fine. But again, with heavy usage the random part of the random generator did not work so well.

I knew of a built-in C function that could do the job, but somehow that was not the first place I looked. I was also keen on providing the most compact solution. In the end, an ILE C program looked like the best solution, until I found a much more elegant way to do things: "Prototyping C library functions in RPG IV".

One of my colleagues had brought back from COMMON a Lotus Freelance presentation by Jon Paris (of IBM) showing the use of Prototypes and Functions within ILE RPG. In a nutshell, this technique allows the programmer to access the more sophisticated C functions without having to call a separate program. The C functions (which are in a Service Program) are linked to the RPG program.

To illustrate this technique, I have copied in this article the prototype that I used to test this new (for me) functionality. My test program shown here is very simple. It generates four random variables in a row and dumps the results. It can be called simultaneously by many users and will consistently yield different random numbers. It took me a while to get from Jon Paris’s COMMON example to the point where I had a usable program. Initially, I found it difficult to see how the elements (two prototyped commands and a parameter) work together. I will share my experience with you by explaining how the prototyping process works in the random generator program shown below.

The two functions I used in the prototype shown below are SeedRandom and GetRandom (lines 21 and 23). The SeedRandom connects an RPG function to the "srand" C function and the GetRandom connects another RPG function to the C "rand" function.

The "srand" and "rand" functions are connected with each other. The random seeding function "srand" tells any subsequently called "rand" function to start its randomizing process from a given point that you can control, rather than at the default starting point, which is usable, but over which you have no control.

The way to prototype or declare "srand" and connect it with its seed is to declare it first in the D specs (see line 21). The seed parameter for this function should be positioned on the line immediately following (see line 22). In my example, this connects the parameter SeedP to the function SeedRandom. The "rand" function is then declared. It does not require any parameters (see line 23).

Once the "srand" and the "rand" functions are prototyped and parametered in the D specs, see the following steps:

For the seed of the "srand" function, in this program I have used the sum of the job number (unique for every job), the time of day (HHMMSS) and the milli-seconds from the TIMESTAMP field. In actual fact, you don’t have to go that deep. Using the job number and the HHMMSS time should be enough for most applications.

In the comment part of the program (lines 7 to 12), the compiler instructions are spelled out. I found this to be a useful thing to do, as these compiler options are not exactly obvious to everybody. Also, if two years from now you have to re-compile the code, this will be welcome information to have handy, unless you do that type of work fairly often. Basically, the only difference with a "normal" RPG compilation is that you need to have the QC2LE binding directory included at compile time. This binding directory resides in QSYS. This gives the compiler access to the C language functions that will be used inside the program.

There is a lot more that this technique can do for you. The C language is very strong in the math department. This as opposed to RPG, which does not go much beyond add, multiply, subtract and divide. Using this technique within an RPG program, you can calculate trigonometric functions like sine, cosine, tangent, log and more. Complex formulas are also a C strong point and this technique will allow you to conveniently do in C what would require more effort in RPG. You can also access C to create variable length arrays, sort arrays, or use any C function that you might have thought you needed a C compiler to access.

Beyond C language’s math functions, there are also TCP/IP sockets that can be driven directly from your RPG program. According to Jon Paris, most system APIs are bindable and written with the C programmer in mind.

The best news, also according to Jon Paris, is that all this is FREE! You do not have to have the C compiler on your AS/400 to use this functionality. So, for all of you out there who need only parts of C but do not care to purchase the language, this lesser known function will give you the best of both worlds.

For more information, see the following:

"C Library Ref." SC09-2119

"ILE C/400 Programmer’s Ref." SC09-2070

"System API Ref. OS/400 UNIX-type APIs" SC41-4875

"MI Functional Ref." SC41-4810

"ILE C/400 Programmer’s Ref." SC09-2070

"ILE C/C++ MI Library Ref." V3R7

"OS/400 Sockets Programming V3R6" SC41-4422 (TCP/IP)

"CPA Toolkit/400 Ref." SC41-4802

The author thanks Jon Paris of IBM for his valuable help on this subject. Thanks Jon!

 

Example Code using a C function in an RPG program to generate 4 different random numbers in a row:

0008.00 * -----------|------------------------------------------------- *

0009.00 * Description| Program to Randomly generate a 4 digit *

0010.00 * | number and dump the results. *

0011.00 * | This is a prototype only. *

0012.00 * ============================================================= *

0013.00 * WARNING ! ! ! SPECIFIC COMPILATION ! ! ! WARNING *

0014.00 * To compile this program properly you will have to use the *

0015.00 * following option : *

0016.00 * CRTBNDRPG DFTACTGRP(*NO) *

0017.00 * BNDDIR(QC2LE) *

0018.00 * This is to allow the called function 'rand' to be retrieved *

0019.00 * from a non-RPG program library. *

0020.00 H DEBUG

0021.00 D SeedRandom PR 10I 0 ExtProc('srand')

0022.00 D SeedP 10U 0 Value

0023.00 D GetRandom PR 10I 0 ExtProc('rand')

0024.00 * Regular numeric variables to receive result of random function.

0025.00 D #Num1 S 5P 0

0026.00 D #Num2 S 5P 0

0027.00 D #Num3 S 5P 0

0028.00 D #Num4 S 5P 0

0029.00 * LongTime has a "Z" datatype, the 20 byte timestamp.

0030.00 D TimeStampZ S Z

0031.00 * From Program Status Data Structure

0032.00 * Job Number, to be used to make a unique number in the data structure.

0033.00 DMYPSDS SDS

0034.00 DJOB_NUM 264 269S 0

0035.00 * Alpha Time Stamp from the TIME Instruction in the "Z" type var.

0036.00 DDSTimeStamp DS

0037.00 D ASMil 21 26S 0

0038.00 D AlphaTime 1 26A

0039.00 **************************************************************************

0040.00 *

0041.00 * New Random with Time & Jobnumber combined as a seed.

0042.00 *

0043.00 C TIME TimeStampZ

0044.00 C MOVE TimeStampZ AlphaTime

0045.00 C TIME DATTIM 6 0

0046.00 *

0047.00 * Regular GetRandom with rand function

0048.00 C CallP SeedRandom(JOB_NUM + DATTIM + ASMil)

0049.00 C EVAL #num1 = GetRandom

0050.00 C EVAL #num2 = GetRandom

0051.00 C EVAL #num3 = GetRandom

0052.00 C EVAL #num4 = GetRandom

0053.00 **************************************************************************

0054.00 *

0055.00 C DUMP

0056.00 C MOVE *ON *INLR

****************** End of data ********************************************

Back to Tylogix Home Page