A pointer is a type of RPG IV field, just like any other field. Pointer fields contain a specific kind of data that is interpreted as a memory address. Suppose your system has 1 GB of memory installed on it. Theoretically, a pointer in a program running on that system could have the memory address for any of those 1 billion bytes of memory. In reality, it could probably contain many more than 1 billion addresses because OS/400 uses a form of virtual storage.
In RPG IV programs, you use memory addresses today without thinking about them. For example, when you pass parameters from one program to another, you pass the address of the field you are passing, not the data itself. This is referred to as "pass by reference."
Each field declared in an RPG IV program is automatically assigned a memory address at runtime. If a character field is declared with a length of 100, 100 bytes of memory are allocated for the field. The field is assigned the address of those 100 bytes.
Suppose you had the ability to retrieve the address of that 100-byte field in that same RPG IV program. What if you could look up the address of the field and copy that address into another field in our program? Well, you can.
RPG IV has a built-in function named %ADDR that returns the memory address of any field declared in the program. The following example illustrates how you can use the %ADDR built-in function to retrieve the address of a field and then copy that address into a pointer field.
0002 D ptr S *
*
0004 C Eval ptr = %addr(CSTNAM)
On line 1 in this example, the CSTNAM field is declared with a length of 100 and a data-type of character. On line 2, the field named PTR is declared with a data type of pointer. When a program containing these three lines is run, storage for the CSTNAM and PTR variables is automatically allocated. One hundred bytes is allocated for the CSTNAM field, and 8 bytes is allocated for the PTR field.
On line 4, the %ADDR built-in function is used to copy the memory address assigned to the CSTNAM field to the PTR field. If, at runtime, the CSTNAM field is assigned the memory address of 0DEF5640:0001F3CA, the %ADDR built-in function (line 4) extracts that address and copies it to the PTR field. PTR is not a pointer to the memory allocated for the CSTNAM field.
What Good Is a Pointer?
In the previous example, a pointer is simply used to store the memory address of another field. That by itself isn't very interesting or useful in RPG IV. To take advantage of the pointer value stored in the PTR field, you need another variable declaration in the program. In the example below, I've added one more Definition specification to the previous example.
0002 D ptr S *
0003 D Buffer S 100A BASED(ptr)
*
0004 C Eval ptr = %addr(CSTNAM)
In this example, line 3 is added to declare the BUFFER field. The BUFFER field is a "based" variable; that is, it includes the BASED keyword. Whenever a field is declared with the BASED keyword, no storage (meaning no memory) is allocated at a program's start time for that variable. A based variable only provides access to the memory address stored in its associated pointer field.
This means that the memory at whatever address is stored in the PTR variable may be manipulated (viewed, copied, changed) through its based variable (the BUFFER field in this example). You can change the memory at the address stored in the PTR variable by simply modifying the content of the BUFFER field.
In the second example, the CSTNAM field is 100 bytes long, as is the BUFFER field. After line 4 is run, the PTR field contains the memory address of the CSTNAM field. Therefore, after line 4 is run, the memory automatically allocated for the CSTNAM field is also visible through the BUFFER field. In other words, they both reference the same location in memory.
Pointers are useful when you need to access a memory location through multiple based variables--for example, when you have a large, unformatted field/buffer that needs to be accessed and manipulated at runtime or when a data structure just isn't a good fit for the problem.
Pointers also provide a way for you to determine at program runtime whether or not you actually need to use a certain field. For example, if you don't need the data structure named COMPINFO (see Figure 1), why have the storage for the data structure automatically allocated? You can simply allocate the storage for COMPINFO when you need it.
|
Figure 1: Dynamically allocated memory
The COMPINFO data structure is a long variable. The program that uses COMPINFO does not always need to store data in it. Sometimes, when the program runs, the data structure is ignored. By basing the data structure on a pointer, the data structure becomes a based variable, and no storage for it is allocated at program runtime. Instead, when the data structure is needed, the program allocates storage for it, using the ALLOC opcode or %ALLOC built-in function depending on the version of OS/400 you compiled the program on. This technique frees up the storage for COMPINFO when it is not needed. Of course, by allocating the memory for the COMPINFO field at runtime, it is your responsibility to deallocate it using the DEALLOC operation code. This is usually done just before the program ends.
Based variables can act as a window into another field's memory, or they can have their own memory allocated for them at runtime. Pointers provide the ability to do these kinds of things, and although they are interesting data types, you should consider them only when no other natural RPG IV method is available.
"Module Where Used" Utility
As promised last time, I have posted the Module Where Used utility for download. The utility is very basic. It creates a list of modules used for a program or service program. You can generate the list using generic, full, or *ALL program names. I have written a command wrapper for the utility. The syntax for this command is as follows:
The CRTMODXREF command generates a database of *MODULE where used information. Enter the program name (generic, full, or *ALL) along with the library name (*ALL, *ALLUSR, *USRLIBL, or *CURLIB), and specify the type of objects to add to the list. Valid choices are *PGM or *SRVPGM.
Download the source code here.
Bob Cozzi has been programming in RPG since 1978. Since then, he has written many articles and several books, including The Modern RPG Language --the most widely used RPG reference manual in the world. Bob is also a very popular speaker at industry events such as COMMON and RPG World and is the author of his own Web site, rpgiv.com.
LATEST COMMENTS
MC Press Online