Using variadic functions within variadic functions

P

pinkfloydhomer

Can I use printf inside a variadic function that I am writing?

Like:

void print(const char * format,...)
{
va_list va;
va_start(va, format);
char buffer[64*1024]; // yeah, I know...
vsprintf(buffer, format, va);
va_end(va);
printf("--- %s ---", buffer);
}

I know the example is degenerate, but is it allowed, that is, does it
have welldefined behavior?

I would imagine that printf itself would also have need for the
va_list, va_start etc. mechanism.

/David
 
?

=?ISO-8859-1?Q?=22Nils_O=2E_Sel=E5sdal=22?=

Can I use printf inside a variadic function that I am writing?

Like:

void print(const char * format,...)
{
va_list va;
va_start(va, format);
char buffer[64*1024]; // yeah, I know...
vsprintf(buffer, format, va);
va_end(va);
printf("--- %s ---", buffer);
}

I know the example is degenerate, but is it allowed, that is, does it
have welldefined behavior?

If 'buffer' contains a string, printf("--- %s ---", buffer);
is ok, and legal. No magic tricks here, and this has nothing to
do with varargs.
 
D

Dave Thompson

Can I use printf inside a variadic function that I am writing?
Like:

void print(const char * format,...)
{
va_list va;
va_start(va, format);
char buffer[64*1024]; // yeah, I know...
vsprintf(buffer, format, va);
va_end(va);
printf("--- %s ---", buffer);
}

I know the example is degenerate, but is it allowed, that is, does it
have welldefined behavior?
As long as a similar direct call to s[n]printf would, namely: you
don't overflow buffer, a risk you already alluded to, and could
protect against in C99 by using vsnprintf; and the data arguments you
receive and pass on using va correctly match the format specifiers.
(And don't overlap, but nothing validly provided by the caller can
overlap your 'auto' buffer.) And you don't overflow the stack.
I would imagine that printf itself would also have need for the
va_list, va_start etc. mechanism.
No problem; varargs works separately for each vararg function. You can
have vararg call vararg, vararg call nonvararg, vararg call nonvararg
that calls vararg, etc., etc. The only thing you can't do is pass your
own varargs on to another routine _as varargs_; instead you pass the
entire list (or a suffix of it) as a va_list -- as you correctly do.

The other thing to be careful of is that you can't pass 'your' va_list
to a function that uses it to access the arguments (like vs[n]printf
usually) _and_ use that same va_list to access the arguments yourself,
because it is unspecified whether va_list is an array 'by reference'
type or not. In C99 you can use va_copy to handle this. Or, even in
C89, you can start, use and end two va_list objects explicitly; or one
object with distinct (non-overlapping) ranges.

Oh, and to be super-picky: your 64*1024 is nominally done in 'int'
arithmetic, which is allowed to be only 1+15 bits and could overflow.
In practice this will always be done at compile time and should be at
least diagnosed, but is not strictly required to be. Moreover, 65536
chars is greater than the minimum object size that must be supported,
even (very slightly) in C99, and exceeding a resource limit isn't
required to be diagnosed, although compile-time cases should be.

And finally, it is implementation-dependent whether the last line of a
text stream (which stdout is) must end in a newline. Your function by
itself is valid, but if used in a program that does not subsequently
output a newline on such a system it won't work as desired.

- David.Thompson1 at worldnet.att.net
 

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,774
Messages
2,569,598
Members
45,150
Latest member
MakersCBDReviews
Top