vsprintf(char *str, const char *format, va_list ap, ...)?

G

goldfita

My last post -
http://groups.google.com/group/comp.lang.c/browse_thread/thread/eacc2938b4c8ee66/0bdf6ab20a6007d0

I have a little bit more challenging question this time. Suppose I
have

write_cmd(struct ast_connection *conn, char *msg, ...);

I want to call it like (forgive the syntax)

write_cmd(conn, str, p1, p2, ..., pn, k1, k2, ..., km);

The parameters p1 to pn must be passed to write_cmd every time. The
parameters k1 to km are not actually constant, but they are accessible
from conn; so, I don't really need to pass them in. It would be better
to call

write_cmd(conn, str, p1, p2, ..., pn);

However, as noted in the last post, I want to print the parameters
using vsprintf, which means they all need to be in the list. I could
follow vsprintf with sprintf to get the rest of k1 to Km, and thus
roughly double both the buffer space and processing time. But this
seems silly given that I could get those parameters into the list by
calling the first write_cmd.

I have some code which obviously doesn't work. But you can probably
see what I'm aiming for. I could probably also do it with a vsprintf
that took a list and a variable number of parameters, if there were
such a thing...

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

void vvfunc(char *msg, va_list argp, va_list argp2)
{
char buf[128];

vsprintf(buf,msg,argp); //argp2 goes here
puts(buf);
}

void vfunc2(char *msg, va_list argp, ...)
{
va_list argp2;

va_start(argp2,argp);
vvfunc(msg,argp,argp2);
va_end(argp2);
}

void func(char *msg, ...)
{
va_list argp;

va_start(argp,msg);
vfunc2(msg,argp,10); //k1
va_end(argp);
}

int main(void)
{
func("hello %s %d\n","there"); //p1
return 0;
}
 
J

JesusWaffle

I don't think there's any way to do this portably. The only solution I
can think of is to implement your own vvsprintf() function which takes
two va_lists.
 
G

goldfita

I don't think there's any way to do this portably. The only solution I
can think of is to implement your own vvsprintf() function which takes
two va_lists.

Darn, that's kind of what I figured. I thought about implementing a
vvsprintf, but it's not worth it.
 
K

kyle.tk

My last post -
http://groups.google.com/group/comp.lang.c/browse_thread/thread/eacc2938b4c8ee66/0bdf6ab20a6007d0

I have a little bit more challenging question this time. Suppose I
have

write_cmd(struct ast_connection *conn, char *msg, ...);

I want to call it like (forgive the syntax)

write_cmd(conn, str, p1, p2, ..., pn, k1, k2, ..., km);

Variable lists are, well, variable. There would be no way to know where
the first variable list ends and the next one begins.

va_arg lists always have to have "..." as the last argument in the
function argument list.

-kyle
 
R

rory.brandybuck

There is a portable way to do it.
Replace va_arg lists by arrays and use initializers to init. the arrays
before the function call:

write_cmd(Connection_t* conn, char* str,
PParameter_t p[], int p_size,
KParameter_t k[], int k_size) ;
....
KParameter_t k[] = {{INT,1}, {INT,2}};
....
write_cmd(conn, str, p, p_size, k, SIZEOF(k)) ;
....


See example:
#include <stdio.h>

#define SIZEOF(array) \
sizeof(array) / sizeof((array)[0])

/*NOTE: belowed struct/union(s) members' names make no sense.
They have taken just for example.
*/
typedef enum{
FAKE_ARRAY, INT, STRING
} Typecode; /* use the same Typecode type in both
PParameter and KParameter for simplicity */

typedef struct Connection{
/* ... */
int fake_int;
char* fake_pchar;
} Connection_t;


typedef struct PParameter {
Typecode type;
union{
/* ... */
int fake_array[2];
char* fake_pch;
} u;
} PParameter_t;

typedef struct KParameter {
Typecode type;
union{
/* ... */
int int_fake;
char* pchar_fake;
} u;
} KParameter_t;

void
write_cmd(Connection_t* conn, char* str,
PParameter_t p[], int p_size,
KParameter_t k[], int k_size) {
int i;

printf("str: \t%s\n", str);

/* print p[] */
printf("p: ");
for (i = 0; i < p_size; ++i)
switch(p.type) {
case STRING:
printf("\tstring: %s\n", p.u.fake_pch);
break;
case FAKE_ARRAY:{
int j;
printf("\tarray: ");
for(j = 0; j < SIZEOF(p.u.fake_array); ++j)
printf("%d, ", p.u.fake_array[j]);
printf("\n");
break;
}
};

/* print k[] */
printf("k: ");
for (i = 0; i < k_size; ++i)
switch(k.type) {
case INT:
printf("\tint: %d\n", k.u.int_fake);
break;
case STRING:
printf("\tstring: %s\n", k.u.pchar_fake);
break;
};
}
int main() {
Connection_t conn;
/* Tested on:

Comeau C/C++ 4.3.3 (Aug 6 2003 15:13:37) for
ONLINE_EVALUATION_BETA1
MODE:strict errors C99

And:

gcc.exe (GCC) 3.4.4 (mingw special)
default compiler settings
*/
PParameter_t p[] = {{STRING, .u.fake_pch = "a string"},
{FAKE_ARRAY, {1,10}},
{STRING, .u.fake_pch = "another string"}
}; /* C99 mode initializer used */
KParameter_t k[] = {{INT,1}, {INT,2}};

write_cmd(&conn, "just a string", p, SIZEOF(p), k, SIZEOF(k));
}
 

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,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top