A printf
function-like call from a function with variable number of arguments is easy enough to make - just use a v -version of those functions ( vprintf
, vsprintf
, CString::FormatV
, etc). But what if I'm chaining the calls up? Here's the simple code:
#include <stdarg.h>
#include <iostream>
void direct(const char * _fmt, bool _extra, ...){
va_list args;
va_start(args, _extra);
char ca[200];
vsprintf(ca, _fmt, args);
std::cout << ca << std::endl;
va_end(args);
}
void chained(const char * _fmt, ...){
va_list args;
va_start(args, _fmt);
direct(_fmt, false, args);
va_end(args);
}
int main(){
direct("direct works just fine: %d", false, 1);
chained("indirect produces garbage: %d", 1);
return 0;
}
A sample output is as follows:
direct works just fine: 1
indirect produces garbage: 1951661256
I feel that I'm missing something obvious but can't figure it out thus far. Please help me fix it so that whether I call direct
or chained
the code works properly.
Flagged the question as C/C++ but I prefer a C++ answer (if there's a difference)
I feel that I'm missing something obvious but can't figure it out thus far
You did. And it's something you actually started with: "just use a v-version of those functions" . The reason those functions got a v-version was to allow, as you called it, chaining them. So if you want to support it for your own printf-like function, make sure to follow the same practice:
void direct_v(const char * _fmt, bool _extra, va_list args){
char ca[200];
vsprintf(ca, _fmt, args);
std::cout << ca << std::endl;
}
void direct(const char * _fmt, bool _extra...){
va_list args;
va_start(args, _extra);
direct_v(_fmt, _extra, args);
va_end(args);
}
void chained(const char * _fmt...){
va_list args;
va_start(args, _fmt);
direct_v(_fmt, false, args);
va_end(args);
}
A nice emerging property of splitting direct
like this is that you get better separation of concerns. The wrapper does the va_list
related bit, and the v-function only cares about what needs to be done with the list, which is what allows for reuse here.
Pre-edit note: BTW, if C compatibility is indeed a concern, the function prototypes need a comma to separate the last argument from the ellipsis. The syntax you used is C++ only.
You cannot chain calls to C-style variadic functions. The only way is to pass va_list
as an argument. This is exactly the reason why the v* family of functions is needed.
So you write your v*-like functions in terms of va_list
, and then wrap each one in an ellipsis-based variadic function.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.