|
||||||||
|
|
![]() |
|
|
|
|
||
|
Returning a Pointer to a Data Structure from a Function by Steven Gray Working with pointers can be a challenge. As iSeries developers using RPG, we need challenges to keep our bragging rights, but most of our day-to-day decisions are based on real business needs and long-term practicality. And though we know RPG can do almost everything C++ can do, none of us wants some maintenance programmer to suffer with something we wrote years ago just to prove our manliness. Nor do we want to untangle something we ourselves wrote when we were youthful and adventurous. Sometimes pointers are just a very effective way of passing data. A data structure, for example, is a good way to return a lot of data from a procedure as a single item. Creating a function that returns a data structure is efficient, but setting up the procedure interface can require some extra thought. Here's a technique I use to simplify the call and to exploit the compiler's ability to do much of the work for me. I can use standard RPG technique and still get the thrill of calling a function that returns a pointer to a data structure. First, I create a function that returns my data bundled in a string. The string actually contains the data structure that I load with whatever values I need. Bundling the inbound data in a string, and putting all outbound parameters as read-only, makes maintenance easier. It's also more readable. Then all that's left is to load my target data structure with the data in the string. This is a snap to do by using the %STR() built-in function. The function %STR() looks at the pointer that is returned and sees it as the first character of a string. It loads the first character onto the data structure and continues to unwind, loading the remaining characters onto the data structure until it comes to the end of the string. I will mark the end of the string with the standard hex"00". One line of code calls the function and loads the data structure from the pointer. Here's what it looks like in the calling program: FCustomer IF E K DISK rename(Customer:Cfmt) * funct prototype D getCustDS PR D pCustNum 05P 0 value * D CustDS DS D CustNum 10S 0 D Name 40 D Addr 40 D CityStZip 40 D CurBal 9S 2 D CredBal 9S 2 * D zCustNum S 10S 0 * C Eval zCustNum = 1001 * call function and use %str() to load DS C Eval CustDS = %str( getCustDS(zCustNum) ) * do other stuff here C Eval *inlr = *on This method also simplifies the procedure interface. A pointer to a string is all that is returned by the function. Passed parameters are not returned, allowing the use of pass by VALUE. Using the keyword VALUE tells the compiler to create a copy of the data to be passed to the function and also to fix any data type differences it might find, which means less maintenance for me. (I intentionally created a type mismatch here to show how this feature works.) Here's all that's needed to begin the procedure. P getCustDS B D getCustDS PI * D zCustNum 05P 0 value The body of the function contains just regular RPG code. Here I do all the normal work to assemble data and load a local copy of the customer data structure. D CustDS DS D CustNum 10S 0 D Name 40 D Addr 40 D CityStZip 40 D CurBal 9S 2 D CredBal 9S 2 * D ReturnStr S 200 inz(*blanks) * C pCustNum Chain cfmt C If %found * load DS here C Eval CustNum = CustomerNo C Eval Name = %trim(FName) + ' ' + C %trim(MidInit) + ' ' + C %trim(LName) + ' ' C Eval Addr = address1 C Eval CityStZip = %trim(city) + ', ' C + %trim(state) + ' ' C + %trim(zipcode) C Eval CurBal = Balance C Eval CredBal = Credit - Balance C Else C Eval CustNum = *zeros C Endif When I have finished loading the local copy of the data structure, it needs to be converted to a string before passing it back to the calling program. There are a number of ways to do this, but to keep things simple here, I append a NULL to the data structure and copy it to a character variable. This fills the requirements for a string. The function returns with the address of the variable. C Eval ReturnStr = ReturnDS + X'00' C Return %addr( ReturnStr ) P getCustDS E Again, when my function returns, the %STR() BIF will load my target data structure, starting from the first character and continuing to the first NULL it finds. The important thing to keep in mind is that the attributes of the local copy of the data structure in the function and the target data structure must match. Using an external data structure or a /COPY member could simplify this. For this example, I have put the function at the end of the source member. For use in production, the function should be put in a service program. And, of course, put your prototype in a separate /COPY member. To test this example, I have included sample SQL statements you can use to create and load the CUSTOMER file. Steven Gray is a consultant for Paradigm Business Solutions, a Lawson and Microsoft business partner. He has worked with the AS/400 and iSeries for over 16 years, starting with the S/38. E-mail: steven.gray@rcn.com
|
Editors
Contact the Editors |
| Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved. |