[comp.lang.c] varargs strangeness?

jcl@bdrc.UUCP (John C. Lusth) (12/17/88)

I have a variadic function to which I pass a pointer to a function returning
void.  Distilled, my function looks like

error (va_alist)

va_dcl

{
    va_list	ap;
    void	(*f)();

    va_start(ap);

    f = va_arg(ap, void (*)());
    .
    .
    .
}

It is at the assignment to f that the compiler complains

    "syntax error at or near symbol *"

On a SUN 4, the macro call va_arg(ap, void (*)()) expands to

    f =  (( void (*)() *)(ap += sizeof( void (*)())))[-1];

What's going wrong, how do I fix it, and why does the macro add
that extra star to the cast?

John C. Lusth
Becton Dickinson Research Center -  "designing the Ace Bandage of the future!"
bdrc!jcl@mcnc

gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/17/88)

In article <353@bdrc.UUCP> jcl@bdrc.UUCP (John C. Lusth) writes:
>What's going wrong, how do I fix it, and why does the macro add
>that extra star to the cast?

You basically answered your own question -- the * is added in
order to get a pointer to the right type and of the right width,
and that is what breaks in your case, because not all types can
correctly have * appended to produce pointers to those types.

The obvious solution is to use a typedef for (void (*)()) and
use that in the invocation of va_arg().

ark@alice.UUCP (Andrew Koenig) (12/17/88)

In article <353@bdrc.UUCP>, jcl@bdrc.UUCP (John C. Lusth) writes:
> I have a variadic function to which I pass a pointer to a function returning
> void.  Distilled, my function looks like
> 
> error (va_alist)
> 
> va_dcl
> 
> {
>     va_list	ap;
>     void	(*f)();
> 
>     va_start(ap);
> 
>     f = va_arg(ap, void (*)());
>     .
>     .
>     .
> }

The C preprocessor is pretty simple-minded.  This makes it
hard (probably impossible) for varargs to cope with argument
types that cannot be transformed into their related pointer
types by appending a *.

void(*)() is definitely not such a type.

To make it into one, use a typedef:

error (va_alist)

va_dcl

{
    va_list	ap;
    typedef 	void (*voidfuncp)();
    voidfuncp	f;

    va_start(ap);

    f = va_arg(ap, voidfuncp);
    .
    .
    .
}

``C Traps and Pitfalls'' describes varargs.h in some detail
starting on page 134.
-- 
				--Andrew Koenig
				  ark@europa.att.com