我有一个带有不同类型和值的参数struct(这对我的问题并不重要):
enum class ArgType {...}
struct Argument
{
ArgType type;
void* value;
}
我有一个自定义动态List
实现,用于创建Argument
的列表。然后,我有以下功能可以接受此列表,我的目的是遍历此列表并构建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
}
}
然后我有一个名为bar
的函数,它将使用foo
函数构建一个va_list,并将打印一个格式化的字符串。
void bar(char* format_str, List<Argument>* args)
{
// get va_list from: foo(args);
vfprintf(stdout, format_str, argptr);
}
我如何构建va_list
,或制作类似于va_list
的内容,我仍然可以传递给vfprintf
?
提前致谢。
答案 0 :(得分:1)
va_list
只是一个指向已被推入调用堆栈以与函数CALL
指令一起使用的参数的指针。您的链表存在于内存的其他位置。执行所要求的唯一方法是编写枚举列表的汇编代码,并手动将值推送到调用堆栈中。不要这样做,它依赖于编译器,甚至依赖于平台。
你甚至不应该在C ++中使用printf
- 样式的函数开始。改为使用I / O流,例如std::cout
,std::ostringstream
等。为operator<<
写一个Argument
,然后使用普通循环枚举列表并将其值写入您想要的std::ostream
对象。
对于bar()
函数,您只需将format_str
拆分为一个令牌列表,然后将每个令牌写入std::ostream
,替换为Argument
值&#34;特殊&#34;根据需要提供令牌。
或者,您可以完全摆脱bar()
并让调用者使用它想要的任何Arguments
直接格式化其std::ostream
列表。
答案 1 :(得分:1)
在C ++ 11或更高版本中,您应该尽可能使用variadic template。阅读parameter pack s。考虑使用std::stringstream
- s,std::ostringstream
- s等。
如果你真的想在运行时建立一个可变参数调用(但这通常是一个坏主意),你可以考虑使用libffi(它知道你的特定ABI&amp; {{3} },并且有一些汇编程序。)
今天,va_list
需要编译器支持(通过__builtin_va_start
等...)并且您的ABI知道它(因为许多调用约定涉及calling conventions)。请参阅processor registers(并注意其va_copy
)和stdarg(3)。