OK, I know this has been discussed in the past and I've read Barbara's
document on "Converting from C Prototypes to IBM RPG/400 Prototypes" at:
http://www-01.ibm.com/support/docview.wss?uid=nas16e4fc64bf5995b8886256b730054c832
and various other places on the 'net (mostly with no attribution ...
tsk, tsk).
I note that the primary focus is on passing parameters and very little
is said about receiving a return value. I want to get a 1-byte value
back from C but C seems to always widen no matter what I do. My
question relates to the following line in Barbara's document:
:quote.
Note: If the C function is specified #pragma argument(nowiden) for the
function, you should use EXTPROC(*CNOWIDEN). Coding *CNOWIDEN is
necessary for RPG to handle 1C and 1A correctly, when passed by value
or returned.
:equote.
My confusion stems from the fact that if C is instructed to not widen
then why does RPG need *CNOWIDEN when that's RPG's default behaviour?
What is RPG doing that requires it to be *instructed* to behave
differently?
Here's some test code:
C module:
char inttochar( int i )
{
char c = i;
return c;
}
RPG module:
H OPTION(*SRCSTMT : *NODEBUGIO)
H BNDDIR('QC2LE')
D inttochar PR 1 EXTPROC('inttochar')
D int 10I 0 VALUE
D toHex PR EXTPROC('cvthc')
D hex 32766A OPTIONS(*VARSIZE)
D char 16383A CONST OPTIONS(*VARSIZE)
D len 10I 0 VALUE
D msgText S 52
D compileFlagsInt...
D S 10U 0 INZ(X'00000075')
D compileFlags S 1
D compileFlagsHex...
D S 2
C EVAL compileFlags =
inttochar( compileFlagsInt )
C CALLP toHex( compileFlagsHex : compileFlags :
C
%SIZE(compileFlags)*2 )
C EVAL msgText = '0x' + compileFlagsHex
C msgText DSPLY
C SETON LR
C RETURN
Running this code and stepping into inttochar() shows i contains
X'00000075' and c contains x'75'. So far so good. Returning to the RPG
shows compileFlags contains X'00' which is to be expected if a
mismatch in interpretation occurs (i.e., C sticks the value in the
rightmost byte of a 4-byte integer--widened--and RPG only looks at the
leftmost byte).
So to "correct" RPG's behaviour I need to either specify *CWIDEN (to
match C's default behaviour) or code the C function with #pragma
nowiden and specify *CNOWIDEN in RPG. So to test things I add:
D inttochar PR 1 EXTPROC(*CWIDEN : 'inttochar')
and then when I run the program I see compileFlags contains X'75'
exactly as expected and desired. However, I should be able to make
*CNOWIDEN work as long as both C and RPG have the same view of the
world. So I code:
D inttochar PR 1 EXTPROC(*CNOWIDEN : 'inttochar')
in the RPG and add:
#pragma argument ( inttochar, nowiden )
to the C source (before the function definition). When I run the
program I see compileFlags contains X'75' exactly as expected and
desired.
Referring to the C/C++ Compiler Reference I see that the documentation
for #pragma argument says:
nowiden Specifies that the arguments are not widened before they are
passed or received.
Although this implies that it applies only to arguments and not return
values I wonder whether that's true because there seems little point
in supporting a mechanism to match parameters/arguments and not
support matching the return value. (However, I would not be surprised
to learn this is yet another example of ridiculous behaviour in C.)
If that's true then because RPG's default behaviour is to presume no
widening then I should be able to specify no widening in the C
function and leave RPG at the default so I remove *CNOWIDEN from the
RPG prototype. When I run the program I see compileFlags contains
X'00' so we're back to the widening problem.
This supports my presumption that C always widens the return value so
I wonder what happens if I remove #pragma nowiden from the C function
and tell RPG that *CNOWIDEN is actually in effect. I make those
changes and now when I run the program I see compileFlags contains
X'75'. Curiouser and curiouser.
So although C always widens the return value telling RPG that it's not
widened makes things work. Why is that so? Is it because RPG is being
warned that a C function is being called, it knows the C function will
always widen the return value, and so it adjusts which bytes of the
return value it uses according to the size and type of the variable
specified on the left-hand side of the assignment?
My conclusion is that unless I specify either *CWIDEN or *CNOWIDEN I
cannot make C and RPG behave properly and since I have other reasons
for not using those my only option is to write a conversion routine in
a language other than C (e.g., RPG) to convert the int returned by C
into a 1-byte char for use by RPG or COBOL.
Can anyone (hello Barbara) confirm this?
Finally, Barbara's document shows that a C programmer can tell the
compiler not to widen by specifying:
#pragma nowiden(fn)
but that's syntactically incorrect. It probably should be one of:
#pragma argument (fn, [type,] nowiden )
or
#pragma linkage (fn, [type,] nowiden )
Regards,
Simon Coulter.
--------------------------------------------------------------------
FlyByNight Software OS/400, i5/OS Technical Specialists
http://www.flybynight.com.au/
Phone: +61 2 6657 8251 Mobile: +61 0411 091 400 /"\
Fax: +61 2 6657 8251 \ /
X
ASCII Ribbon campaign against HTML E-Mail / \
--------------------------------------------------------------------
As an Amazon Associate we earn from qualifying purchases.