Re: var_args problems in C... any ideas?

Dennis Clark ((no email))
Tue, 13 Dec 1994 11:53:11 +1100 (EST)

In previous mail, Paul Damien Mclachlan writes:
>
>
> OK... here's a toughie...
>
> OK... I'm trying to write a function that is close to scanf, but
> horribly more complex once you look at it. (I think so, anyway)
>
> consider:
>
> void interface( char *typelist, char *instring, void *function )
>
> where typelist is a scanf type string, eg "%c%d%s"
> instring is a list to scan from, eg "a14hello there"
> and function is a function to call. In the above example it would be:
>
> void function( char g, int num, char *str );
>
> see what I mean? I need a way to generate a var_args style list,
> without actually using var_args, because they are just used for reading
> varargs, not passing them, as far as I can tell.

Let's see if I can shed some light on this for you. Firstly, echoing
Chris' words, I too have never written a function using var_args, but a
quick "man 3 varargs" confirmed my suspicion that var_args doesn't
actually generate a list, it merely provides a set of macros for
interpreting the arguments. The arguments themselves are passed to a
var_args function in exactly the same manner as they would be to any
other function.

>
> I'd preferably like a way to do it without having to consider each
> possible permutation of the typelist string, and I'd really like to be
> told it can be done in portable C... I could do it on a PC, with stack
> based passing using just a little hack - but thats not very portable -
> and I wouldn't have a clue how to do it so that it would work on ftoomsh
> anyway!
>

The only really portable way of generating arguments to a C function is
to let the compiler do it. Thus each instance of a function call in a C
program needs to have the number and types of its arguments determinable
at compile time. HOWEVER you can save a fair bit of work in
"considering each permutation" if you are prepared to place the
following restrictions:

a) All arguments must be POINTERS to values.
b) An upper limit on the number of arguments to be passed.

If that seems reasonable, you can take advantage of the following 2
assumptions about C compilers:

1) All pointer types occupy the same amount of memory.
2) The called function cannot tell how many arguments were
actually passed.

Oops, I just realised the first assumption isn't true on 16-bit PC
programs... in that case, the arguments must all be FAR POINTERS.

Having done that, your code will look something like this..

#define MAXIMUM_ARGS 10

void interface( char *typelist, char *instring, void *function() )
{
void * arg[MAXIMUM_ARGS];
int argc = 0;

while (...)
{
if (...)
{
char *c;
...
arg[argc++] = c;
}
else if (...)
{
int *i;
...
arg[argc++] = i;
}
else if (...)
{
float *f;
...
arg[argc++] = f;
}
}

function(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],
arg[6],arg[7],arg[8],arg[9]);
}

Note that passing more arguments than the function actually uses is OK
because of assumption 2. You may wish to type-cast the assignments to
arg[argc++] to prevent your compiler generating annoying warnings, but I
prefer to avoid casting and let the compiler (correctly) tell me I'm
doing something type-unsafe, even if it is deliberate.

> I'd appreciate any help from all you clever ppl out there.... because
> I've spent a day on it and don't have a clue!
>
> Regards,
>
> Paul

Well that's my contribution for ya. Anyone who cares to tell me I'm
wrong about anything I've said, please feel free :)

-- 
Cheers,
    DB