C varargs - problems with va_copy

I am writing a function in C that takes a variable number of arguments.

size_t myprintf(char *fmt, ...); 

So far so good. I decided it was best to do Right Way β„’ things and create a version that accepts variable arguments, and another version that accepts va_list .

 size_t myprintf(char *fmt, ...); size_t myvprintf(char *fmt, va_list args); 

Not so hard. With the exception of my_vprintf() you need to send it args out to two different functions (first up to snprintf() with a length of 0 to determine how much space we need, and then sprintf() after we allocated so much space). I am doing 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 } 

It's all fine and dandy, but the C99 is a little poorly implemented. I would like, if possible, to use my code to work on C89 and work with as many compilers and on as many platforms as possible. I 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 convinced that ((a)=(b)) unreliable and that I should use memcpy() or something like that, but it's still at the level of β€œIf you do not support C99, I hope it works” a not "If you do not support C99, never be afraid" (this is what I want). Is there a good way around this limitation? I saw several solutions - va_list functions that eat one argument and recurs by passing va_list twice to make two separate copies, etc. - but I don’t know how much they will work (and the recursive solution will not be so good if I just want to call vsnprintf() , now will it be?).

So, I am contacting you, a StackOverflow user. Is there anything else I can do to ensure compatibility with C89, or users without va_copy and __va_copy (admittedly few and far apart) to just suck it and take it?

+6
c variadic-functions
source share
1 answer

(a)=(b) is unreliable. Even going through two va_list (public function will be a simple wrapper), since va_list can be something like:

 typedef __va_list_impl va_list[1]; 

for which running va_arg on one will change the other (I seem to remember that Solaris uses such things, oh, register windows ...). Unfortunately, I don’t know which way to do what you want.

+3
source share

All Articles