passing var args as-is to a function

S

sinbad

i have a common function which takes variable parameters as an argument,
depending on the type (the first arg) i want to call the appropriate
function with rest of the param list, is there any way to do this or
any better approach. i'm trying to avoid the switch() statement
below.

void
common_func(int type, ...);

void
do_one(int x, int y);

void
do_two(char a, char b);

void
do_any();

void
common_func(int type, ...)
{
switch(type) {
case 1;
do_one(); /* pass 2,3 */
break;

case 2:
do_two(); /* pass 5,6 */
break;

default:
do_any();

}
return;
}

int main()
{
comon_func(1, ,2 ,3);
comon_func(2, ,5 ,6);
}
 
J

James Kuyper

i have a common function which takes variable parameters as an argument,
depending on the type (the first arg) i want to call the appropriate
function with rest of the param list, is there any way to do this or
any better approach. i'm trying to avoid the switch() statement
below.

It would help to know why you want to avoid the switch() statement.
Every alternative I can think of to the switch statement is just a
different way of implementing a switch (such as if(type==1) {} else
if(type==2) {} else {}). They don't save you any significant amount of
typing, and they won't significantly affect how fast the program will
actually execute. They may make it harder to understand your program,
because the basic logical structure of any function like this
corresponds directly to a switch statement, and using other structure to
achieve the same result would serve only to obscure that fact.
void
common_func(int type, ...);

void
do_one(int x, int y);

void
do_two(char a, char b);

The promoted type of char is 'int' (unless CHAR_MAX > INT_MAX, an
unlikely but possible situation, in which case the promoted type would
be unsigned int). Since the integer promotions are automatically
performed on the variable portion of the argument list, that makes this
a bad choice for an example. If these were the only two options, you
could just define common_func() as taking two additional 'int'
arguments. Passing a double or a char* would have been a better choice.
void
do_any();

void
common_func(int type, ...)
{
switch(type) {
case 1;
do_one(); /* pass 2,3 */
break;

You didn't put in any of the stuff needed to actually handle variable
arguments. Was that just a simplification? Do you know how to use
case 2:
do_two(); /* pass 5,6 */
break;

default:
do_any();

}
return;
}

int main()
{
comon_func(1, ,2 ,3);

The two commas between 1 and 2 are a syntax error.
comon_func(2, ,5 ,6);

Here, too.
 
P

Paul N

i have a common function which takes variable parameters as an argument,
depending on the type (the first arg) i want to call the appropriate
function with rest of the param list, is there any way to do this or
any better approach. i'm trying to avoid the switch() statement
below.

void
common_func(int type, ...);

void
do_one(int x, int y);

void
do_two(char a, char b);

void
do_any();

void
common_func(int type, ...)
{
    switch(type) {
        case 1;
        do_one(); /* pass 2,3 */
        break;

    case 2:
        do_two(); /* pass 5,6 */
        break;

    default:
        do_any();

    }
    return;

}

int main()
{
    comon_func(1, ,2 ,3);
    comon_func(2, ,5 ,6);
}

I think you haven't really thought through what you want. There are
times when you want a different function to be called dependent on a
value that you only know at run-time. This can be done using a switch,
or by a function pointer, amongst other possibilities.

However, here you seem to be wanting to call your common function with
different types or numbers of arguments. At the point of the call, you
have to specify the arguments, and so you apparently know at compile
time what the value of "type" is. So why not just call the function
that you want?

Hope this helps.
Paul.
 
S

sinbad

I think you haven't really thought through what you want. There are

times when you want a different function to be called dependent on a

value that you only know at run-time. This can be done using a switch,

or by a function pointer, amongst other possibilities.



However, here you seem to be wanting to call your common function with

different types or numbers of arguments. At the point of the call, you

have to specify the arguments, and so you apparently know at compile

time what the value of "type" is. So why not just call the function

that you want?



Hope this helps.

Paul.

i have many types, so the switch statement was getting
very big, i'd like to keep the functions as small as
possible. The c-standard pointed to Barry helped.
Thanks Barry. Here's what i want to do, please
point out any problems.

#include <stdio.h>
#include <stdarg.h>

void
common_func(int type, ...);

void
do_one(va_list ap);

void
do_two(va_list ap);

void
do_three(va_list ap);

void
do_any();

#define DO_MAX 4
typedef void (*do_fn)(va_list ap);

do_fn do_fns[DO_MAX];

typedef struct new {
int a;
char b;
}new_t;

void
do_one(va_list ap)
{
int x;
int y;

printf("doing one()\n");

x = va_arg(ap, int);
y = va_arg(ap, int);

printf("x is %u y is %u\n", x, y);

return;
}

void
do_two(va_list ap)
{
char a;
char b;

printf("doing two()\n");

a = va_arg(ap, int);
b = va_arg(ap, int);

printf("a is %c b is %c\n", a, b);

return;
}

void
do_three(va_list ap)
{
new_t *new;
char *c;
int *p;
void *v;

printf("doing three()\n");

c = va_arg(ap, char*);
p = va_arg(ap, int*);
v = va_arg(ap, void*);
new = va_arg(ap, new_t*);

printf("c is %p\n p is %p\n v is %p\n new is %p\n",
c, p, v, new );
return;
}

void
common_func(int type, ...)
{
va_list ap;

va_start(ap, type);

if ((type > 0) && (type < DO_MAX) && do_fns[type]) {
do_fns[type](ap);
}

va_end(ap);
return;
}

int main()
{
new_t *new = (new_t*) 0x2000;
char *c = (char*) 0x4000;
int *p = (int*) 0x8000;
void *v = (void*) 0x9000;

do_fns[0] = NULL;
do_fns[1] = do_one;
do_fns[2] = do_two;
do_fns[3] = do_three;
do_fns[DO_MAX] = NULL;

common_func(1, 2 ,3);
common_func(2, 'a' ,'b');
common_func(3, c, p , v, new);

return(0);
}
 
P

Paul N

I think you haven't really thought through what you want. There are
times when you want a different function to be called dependent on a
value that you only know at run-time. This can be done using a switch,
or by a function pointer, amongst other possibilities.
However, here you seem to be wanting to call your common function with
different types or numbers of arguments. At the point of the call, you
have to specify the arguments, and so you apparently know at compile
time what the value of "type" is. So why not just call the function
that you want?
Hope this helps.

i have many types, so the switch statement was getting
very big, i'd like to keep the functions as small as
possible. The c-standard pointed to Barry helped.
Thanks Barry. Here's what i want to do, please
point out any problems.

#include <stdio.h>
#include <stdarg.h>

void
common_func(int type, ...);

void
do_one(va_list ap);

void
do_two(va_list ap);

void
do_three(va_list ap);

void
do_any();

#define DO_MAX 4
typedef void (*do_fn)(va_list ap);

do_fn do_fns[DO_MAX];

typedef struct new  {
    int a;
    char b;

}new_t;

void
do_one(va_list ap)
{
    int x;
    int y;

    printf("doing one()\n");

    x = va_arg(ap, int);
    y = va_arg(ap, int);

    printf("x is %u y is %u\n", x, y);

    return;

}

void
do_two(va_list ap)
{
    char a;
    char b;

    printf("doing two()\n");

    a = va_arg(ap, int);
    b = va_arg(ap, int);

    printf("a is %c b is %c\n", a, b);

    return;

}

void
do_three(va_list ap)
{
    new_t *new;
    char  *c;
    int   *p;
    void  *v;

    printf("doing three()\n");

    c   = va_arg(ap, char*);
    p   = va_arg(ap, int*);
    v   = va_arg(ap, void*);
    new = va_arg(ap, new_t*);

    printf("c is %p\n p is %p\n v is %p\n new is %p\n",
           c, p, v, new );
    return;

}

void
common_func(int type, ...)
{
    va_list ap;

    va_start(ap, type);

    if ((type > 0) && (type < DO_MAX) && do_fns[type]) {
        do_fns[type](ap);
    }

    va_end(ap);
    return;

}

int main()
{
    new_t *new = (new_t*) 0x2000;
    char  *c   = (char*)  0x4000;
    int   *p   = (int*)   0x8000;
    void  *v   = (void*)  0x9000;

    do_fns[0]      = NULL;
    do_fns[1]      = do_one;
    do_fns[2]      = do_two;
    do_fns[3]      = do_three;
    do_fns[DO_MAX] = NULL;

    common_func(1, 2 ,3);
    common_func(2, 'a' ,'b');
    common_func(3, c, p , v, new);

    return(0);



}

I haven't checked in detail, but at a quick glance, yes that looks
right and is what you were asking for.

It's still a mystery to me why you need to make all the calls through
the same function "common_func", since your program apparently knows
which function it wants to call. I was just suggesting that you
consider whether this is actually required.
 
S

sinbad

Paul,

the common_func() does some more functionality which
is common to all the do_ functions, and it also allows
me to browse through all the instances where the do_
funcrtionality is invoked, meaning it's easy to browse
the code to check where all it is called, that is one
more reason why i want to use common_func.

-sinbad
 
M

Mark Bluemel

Paul,

the common_func() does some more functionality which
is common to all the do_ functions,

So split the common functionality out and call it from all the do_
functions.

and it also allows
me to browse through all the instances where the do_
funcrtionality is invoked, meaning it's easy to browse
the code to check where all it is called, that is one
more reason why i want to use common_func.

Which, being translated, means "I am going to artificially structure my
code to suit some spurious measure of programmer convenience, rather
than structure it based on function".

Hint: http://en.wikipedia.org/wiki/Ctags
 
B

Barry Schwarz

The problem is fundamental. The C language does not provide a method to
pass the ... arguments to another function as arguments.

Sure it does. In C99, it is in paragraph 7.15 of n1256
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top