On 10/03/2009, at 2:55 AM, Elvis Budimlic wrote:
What I went with in the rare cases where I did use them was the
'sentinel'
concept. One of my college professors liked it and it stuck with me.
Basically, you designate a special value (i.e. NULL) as the list
terminator
(aka sentinel). Then the doStuff() function processes the list
until it
hits the sentinel.
I've used that approach when passing in an array of pointers to stuff
to process. The last element in the array is NULL and that acts as
the sentinel. I'd have to rework the interface to make that work in
this situation and it would be contrived and therefore unclean.
As far as I know, this is the issue with all C implementations, not
just the
IBM i.
That was my guess too. The core of C implementations tends to be
fairly standard.
For the relative 'safety' it provides, I actually like your #1
approach.
That's how main() works and for most C developers it wouldn't be a
big leap
to understand the concept (i.e. for the consumers of your doStuff()
function).
However with main() the "number of args" parameter is fairly
transparent. Although the callee needs to check it the caller does
not need to set it. It's done by the system.
I'd like something similar. I woke up this morning thinking perhaps
Operational Descriptors could help. If I tell the compiler to supply
an OpDesc for these functions it will set the number of parameters.
The only issue is retrieving it. Sensible languages provide a means
of determining the number of parameters received. C doesn't and the
CEE APIs for OpDescs also don't give this value either. An oversight
I would have thought since it is part of the information available in
the descriptor structure. A CEEARGC API would be a useful thing to have.
There is an MI instruction NPM_PARMLIST_ADDR which is surfaced as
built-in _NPMPARMLISTADDR which will give the caller access to the
parameter list information. This method requires that an OpDesc is
passed and will correctly provide the number of parameters passed by
the caller.
My solution is to call _NPMPARMLISTADDR and extract the number of
arguments then use this value to condition the va_arg macro calls to
only extract values I **KNOW** are on the stack.
It's not a cross-platform solution but it's unlikely this code will
ever run on other than XPF so I can live with it. If I do need to
port it in the future a set of #ifdef blocks around this code will
allow it to compile and the caller will be required to pass NULL or 0
for the optional parameters--making them required even though the
prototype says otherwise. I could, if I chose, lie by providing a
different #include for the consumer that replaced the ellipses with
required parameters. The compiler would require the caller to pass
something for those parameters and the underlying code could still
use va_arg to address them. Win-win even if a bit obscure however the
obscurity would only be with the maintainer of the underlying code
(i.e., me) and not with the consumer. I can live with that.
Code inside doStuff() looks like:
va_list ap;
_NPM_ParmListAddr_T * plist = NULL;
_NPM_DescList_T * dlist = NULL;
int p2 = 0;
char * p3 = NULL;
double p4 = 0.0;
plist = _NPMPARMLISTADDR();
dlist = plist->dlist;
nbrArgs = dlist->argc;
va_start( ap, p1 );
if ( nbrArgs >= 2 )
p2 = va_arg( ap, int );
if ( nbrArgs >= 3 )
p3 = va_arg( ap, char * );
if ( nbrArgs >= 4 )
p4 = va_arg( ap, double );
va_end( ap );
Now all I need to do is determine how to define an OpDesc for a
function pointer. Compiler barfs but I think I can work around that.
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.