Scott,
As part of constructing the call interface there is always 16 bytes allocated for a return value. This allocation is done by the caller and is true whether or not a return value is defined by the prototype. If the caller prototype DOES have a return value defined and the return value is greater than 16 bytes in length, the caller initializes a pointer into the return value storage which is subsequently used to locate the return value. If the caller is not aware of the return value being greater than 16 bytes in length, then this pointer is not initialized. Any return value less than 16 bytes in length gets stored into the caller allocated storage and/or, in some cases, stored in a register to provider improved performance (which is why data type can be important).
When the called program is ready to return the greater than 16 byte value, it takes the pointer initialized by the caller and then "does some magic" and provides addressibility to the returned value. Now the problem -- this pointer wasn't initialized in our scenario. If that storage just happens to contain a valid pointer, well, undesireable results will most likely occur at some point in that job. If that storage does not contain a valid pointer, probably the more likely case, then you're going to get a MCH and fall into an error path.
This convention for return value handling is independent of the high level language. It is part of ILE implementation rather than a HLL compiler directly generating the correct code.
As for the hand slapping, perhaps I was a little too strong there :) If there's a good reason for doing it, go ahead. But you better remember to prototype that return value (which in your example they clearly would).
I also have to admit that I cheated a little bit here... When I saw your post I was pretty sure about the above, but not sure enough (it's been awhile and I'm getting old) to post immediately. So I did confirm this with one of the ILE architects first :)
Bruce
Bruce Vining Services
507-206-4178
--- On Wed, 11/26/08, Scott Klement <rpg400-l@xxxxxxxxxxxxxxxx> wrote:
From: Scott Klement <rpg400-l@xxxxxxxxxxxxxxxx>
Subject: Re: Calling C from RPG: what am I doing wrong?
To: "RPG programming on the AS400 / iSeries" <rpg400-l@xxxxxxxxxxxx>
Date: Wednesday, November 26, 2008, 12:00 PM
Hi Bruce,
There is a case where storage could inadvertently be overwritten but
it is only when a value is being returned that exceeds 16 bytes in
length.
Really? Can you explain that? That makes little sense to me. The
system reserves 16 bytes for a return value, even if none is declared,
you just can't exceed the 16 bytes???
That's a very weird (and not very intuitive, and not documented
anywhere) thing.
I've had problems with undeclared return values before. If you resolve
a routine via QleGetExp and call it without a return value (assuming the
procedure declares a return value, but your prototype does not) I've had
nasty problems. But, my return values might've been longer than 16
bytes, I don't remember anymore.
I'm assuming that RPG calling C would have the same problems. The RPG
side doesn't know that the C procedure is going to return something,
because it wasn't included in the prototype.
Note that this is a VERY different symptom from declaring a return value
on the prototype and not using it. If it's declared on the prototype,
RPG knows about it, and even if you don't use the return value, the
compiler will handle it properly.
And any developer returning "something" longer than 16 bytes
by value (as opposed to a 16-byte pointer to the "something")
should
have his or her hands slapped.
Then you have a LOT of hand slapping to do, my friend. It's a common
practice in RPG. If you want to return a string from an RPG
subprocedure and use it in an expression, you MUST declare it as a
return value (which is by value). And more often than not, string
values are longer than 16 bytes.
As an Amazon Associate we earn from qualifying purchases.