I'm writing a function in C that takes a variable number of arguments.
size_t myprintf(char *fmt, ...);
So far, so good. I've decided it's best to do things the Right Way™ and make a version that takes variable arguments, and another version that takes a va_list
.
size_t myprintf(char *fmt, ...);
size_t myvprintf(char *fmt, va_list args);
Not that hard to do. Except my_vprintf()
needs to send its args
out to two different functions (first to snprintf()
with a length of 0 to determine how much room we need, then to sprintf()
after we've allocated that much room). I do this with va_copy
.
size_t myvprintf(char *fmt, va_list args)
{
va_list args2;
va_copy(args, args2);
// do stuff with args2
va_end(args2);
// do more stuff with args
}
This is all fine and dandy, but C99 is a bit poorly implemented. I would like, if possible, for my code to work in C89 as well, and to work with as many compilers and on as many platforms as possible. I currently have this after #include <stddef.h>
but before any code:
#ifndef va_copy
# ifdef __va_copy
# define va_copy(a,b) __va_copy(a,b)
# else /* !__va_copy */
# define va_copy(a,b) ((a)=(b))
# endif /* __va_copy */
#endif /* va_copy */
I am led to believe that ((a)=(b))
is unreliable, and that I should perhaps use memcpy()
or something similar, but this is still on the level of "If you don't support C99, I hope it works" rather than "If you don't support C99, never fear" (which is what I want). Is there any good way to get around this limitation? I've seen a few solutions - va_list
functions that eat one argument and recurse, passing the va_list
twice so that two separate copies are made, etc. - but I don't know how well they would work (and the recursive solution won't do so well if I just want to call vsnprintf()
, now, will it?).
So I turn to you, StackOverflow User. Is there anything more I can do to provide C89 compatibility, or are users without va_copy
and __va_copy
(admittedly few and far between) just going to have to suck it in and take it?
(a)=(b)
is unreliable. Even passing two va_list
is (the public function would be a simple wrapper) as va_list can be something like:
typedef __va_list_impl va_list[1];
for which doing a va_arg on one will be modify the other (I seem to remember that Solaris use such kind of thing, ah, the register windows...). Sadly, I know of no sure way to do what you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With