Reputation: 5958
I have an argument struct with different types and values (this is not that important to my question):
enum class ArgType {...}
struct Argument
{
ArgType type;
void* value;
}
I have a custom dynamic List
implementation that I use to create a list of Argument
s. I then have the following function which can take in this list and my aim is to loop through this list and build a va_list
:
void foo(List<Argument>* args)
{
for (int i = 0; i < args->length; i++)
{
Argument* arg = args->get(i);
char* value = (char*) value;
// build a `va_list` from value
}
}
I then have a function called bar
which will build a va_list using the foo
function, and will print a formatted string.
void bar(char* format_str, List<Argument>* args)
{
// get va_list from: foo(args);
vfprintf(stdout, format_str, argptr);
}
How would I build a va_list
, or make something like a va_list
that I can still pass to vfprintf
?
Thanks in advance.
Upvotes: 3
Views: 2581
Reputation: 1
You should prefer, in C++11 or better, using variadic templates when possible. Read about parameter packs. Consider using std::stringstream
-s, std::ostringstream
-s etc.
If you really want to build a variadic call at runtime (but that is generally a bad idea) you might consider using the libffi (which knows about your particular ABI & calling conventions, and has some bits of assembler).
Today, va_list
requires compiler support (thru __builtin_va_start
etc...) and your ABI knows about it (since many calling conventions involve processor registers). See stdarg(3) (and notice its va_copy
) and this.
Upvotes: 1
Reputation: 595712
va_list
is just a pointer to arguments that have been pushed onto the call stack for use with a function CALL
instruction. Your linked list exists elsewhere in memory. The only way to do what you are asking for is to write assembly code that enumerates the list and pushs the values into the call stack manually. Don't do it, it is highly compiler-dependant and even platform-dependant.
You shouldn't even be using printf
-style functions in C++ to begin with. Use I/O streams instead, like std::cout
, std::ostringstream
, etc. Write an operator<<
for Argument
and then use a normal loop to enumerate the list and write its values to your desired std::ostream
object.
In the case of your bar()
function, you could simply split the format_str
into a list of tokens, and then write each token to a std::ostream
, substituting Argument
values for "special" tokens as needed.
Or, you could just get rid of bar()
altogether and let the caller directly format its Arguments
list using whatever std::ostream
it wants.
Upvotes: 1