va_list usage from multiple functions?

S

skillzero

Is there a portable way to process some of a va_list (with va_arg) in
one function then pass that va_list to another function to process
some of the va_list and then go back to the original function to
process the rest of it?

I've implemented a custom printf that handles the normal format
specifiers, but I'd like an extension mechanism so external code can
add custom format specifiers (e.g. MyPrintF( "%d %{xyz} %s", 123,
arg1, arg2, "string" ) where "xyz" and arg1 and arg2 are handled by an
external function). The problem is that the external code would need
access to the va_list and any va_arg's the external code does would
need to be reflected in the original va_list so that when control
returns to the original function, it can continue to use va_arg for
any remaining arguments. The original va_list is passed to my function
as a parameter (like vprintf) so I can't just put the va_list in a
structure and pass a pointer to the structure around.

Since va_list is implementation defined and may be an array type, I'm
not sure how to do this or if it's even possible in a portable way.
 
H

Harald van Dijk

Is there a portable way to process some of a va_list (with va_arg) in
one function then pass that va_list to another function to process some
of the va_list and then go back to the original function to process the
rest of it?

The only portable way to do that is by passing a pointer to it.
I've implemented a custom printf that handles the normal format
specifiers, but I'd like an extension mechanism so external code can add
custom format specifiers (e.g. MyPrintF( "%d %{xyz} %s", 123, arg1,
arg2, "string" ) where "xyz" and arg1 and arg2 are handled by an
external function). The problem is that the external code would need
access to the va_list and any va_arg's the external code does would need
to be reflected in the original va_list so that when control returns to
the original function, it can continue to use va_arg for any remaining
arguments. The original va_list is passed to my function as a parameter
(like vprintf) so I can't just put the va_list in a structure and pass a
pointer to the structure around.

You wouldn't need a structure, you could pass a pointer to the va_list
directly.
Since va_list is implementation defined and may be an array type, I'm
not sure how to do this or if it's even possible in a portable way.

If it's an array type, there isn't be any problem at all: just passing the
va_list would convert it to a pointer. The problem is when it's not an
array type. If you pass a copy of the va_list, and don't have any way to
let the caller know of any updates, the caller cannot do anything about
it.

If you've written the function, why can't you change the interface?
 
S

skillzero

You can pass the subordinate function a pointer to the va_list,
rather than passing its value

Unfortunately, the va_list variant of this function is used by a lot
of higher level code (e.g. vprintf on my system uses my function
underneath) so I can't easily change all the callers to pass a pointer
to the va_list.
 
E

Eric Sosman

Unfortunately, the va_list variant of this function is used by a lot
of higher level code (e.g. vprintf on my system uses my function
underneath) so I can't easily change all the callers to pass a pointer
to the va_list.

If vprintf() calls your function, it's not the Standard
vprintf(). If you've replaced the library's vprintf() with
something else, there's no reason to worry about portability:
it's already been abandoned.

But something's odd here. You said you wanted to implement
a printf-like function with an extension mechanism that would
allow new format specifiers to be defined at run time. Your
example was an "%{xyz}" specifier that would cause MyPrintF()
to call another function, which would in turn consume two of
the arguments from MyPrintF's va_list. Where does vprintf()
come into the picture at all, and why is it a concern?
 
S

skillzero

     If vprintf() calls your function, it's not the Standard
vprintf().  If you've replaced the library's vprintf() with
something else, there's no reason to worry about portability:
it's already been abandoned.

     But something's odd here.  You said you wanted to implement
a printf-like function with an extension mechanism that would
allow new format specifiers to be defined at run time.  Your
example was an "%{xyz}" specifier that would cause MyPrintF()
to call another function, which would in turn consume two of
the arguments from MyPrintF's va_list.  Where does vprintf()
come into the picture at all, and why is it a concern?

vprintf provided by the OS I'm using is limited (e.g. no %zu support)
so I've replaced the implementation with my own to provide all the C99
features. There are also a lot of callers of my function directly. I
can certainly change the interface for my function to take a va_list *
and update all the callers to pass that instead, but there are
thousands of them and some are difficult because the va_list is passed
down through several layers, via callbacks, etc. I was looking for a
way to use a va_list rather than a va_list * to avoid having to make
massive changes like that.
 
T

Tomás Ó hÉilidhe

I've implemented a custom printf that handles the normal format
specifiers, but I'd like an extension mechanism so external code can
add custom format specifiers (e.g. MyPrintF( "%d %{xyz} %s", 123,
arg1, arg2, "string" ) where "xyz" and arg1 and arg2 are handled by an
external function).


I added colour functionality, such as:

^br (black background, red foreground)

So you could have a function call such as:

PrintColourF("My name is ^brFergie ^bwand I have %u kids.",
some_unsigned_int_variable);

Here's my code:

#include <stdio.h> /* printf */
#include <string.h> /* strlen */

#define SPECIAL_CHAR ('^')

static void PrintColour(char *str);

void PrintColourF(char const *str,...)
{
assert(strlen(str) < 1024u);

char buf[2048]; /* Not a great solution */

va_list args;

va_start(args,str);

vsprintf(buf,str,args);

va_end(args);

PrintColour(buf);
}

static void PrintColour(char *str)
{
char *p;

while ( (p = strchr(str,SPECIAL_CHAR)) )
{
*p = 0;

printf(str);

SetCon(p[1],p[2]); /* Here I set the console colour */

str = p + 3;
}

printf(str);
}

As Eric suggested, you can pass the va_list object onto another
function.
 

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

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top