我尝试用C ++为printf写一个包装器。我当然找到了va_list
,但不知道它如何适用于我,因为
包装器将不会直接调用。我将稍后显示。
我解析一个脚本,该脚本包含一个带有未知数量的参数的函数,例如
ASTNode node(Token(PRINT, PRINT));
consume(PRINT);
consume(LPAREN);
node.make_child(variable()); // <-- formatstring (node.child[int])
while(current_token._type() != RPAREN) {
consume(COMMA);
node.make_child(variable()); // <-- the values to replace in formatstring (node.child[int++])
i++;
}
consume(RPAREN);
return node;
第一个将是格式字符串,其他将是要在格式字符串中替换的值,因此我执行它的函数看起来像
if(node._token()._type() == PRINT) {
Token formatstring = visit(*node.child[0]);
Token temp;
int i = 1;
while(i < node.child.size()) {
visit(*node.child[i++]); // <-- the values to replace in formatstring
}
}
,并且不采用任何“真实”参数。如何使用va_list或其他方法构建动态参数数组?
谢谢
编辑:似乎有人不清楚我的问题。
printf的名称像printf(formatstring, param1, param2, param3...)
一样,我想构建在第一个参数(格式字符串)之后传递的参数,例如
// Pseudocode
out("printf(");
out($myformatstring);
int i = 1;
while(i<parameter_count) {
out(parameter[i++]);
out(",");
}
out(")");
答案 0 :(得分:1)
据我了解,您具有给定的格式字符串和“读取/解析”参数。
您要处理两个问题,即处理格式和使用正确的参数类型。
printf
系列不支持部分替换(例如,与Qt相反,Qt允许QString("%1 %2").arg("Hello")
生成QString("Hello %2")
从而允许链接)。
因此,您必须手动解析完整格式的字符串:
在遇到%
时,检索标志格式(除非它是%%
,在这种情况下,直接显示%
)。
从标志格式切换到适当的转换,例如
// flagFormat would "simply" be %i, %010d, %4.2f or %+.0e
switch (format_type) {
case EFormatType::String: // %s
printf(flagFormat, to_string(args[i]).c_str()); break;
case EFormatType::Int: // %i, %d
printf(flagFormat, to_int(args[i])); break;
case EFormatType::String: // %f, %F, %e, %g, %
printf(flagFormat, to_double(args[i])); break;
// ...
}
++i;
答案 1 :(得分:0)
// Pseudocode
// I would like to propose a way to solve the problem, added some stuff here
out("printf(");
// you should create format string in accordance with types of parameters
$myformatstring = "" // let suppose myformatstring is of type "string"
// and it has defined operator "+=" (concatenation of strings)
for(int j = 0;j < parametar_count; j++)
{
switch(parametar[j].type ) // suppose that you have type information of param's
{
case 'i': myformatstring += " %d "; break;
case 'f': myformatstring += " %f "; break;
case 's': myformatstring += " %s"; break;
... // you should handle all types you use ...
}
}
$myformatstring += "\\n\","; // terminate format string and write a comma before
// other arguments...
out($myformatstring);
int i = 1;
while(i<parameter_count) {
out(parameter[i++]);
if( i < parameter_count -1 ) // you don't need comma after last parameter
out(",");
}
out(");");
答案 2 :(得分:0)
/*
there is example that explains how to use stdarg for a function
with variable number of parameters
*/
#include <stdio.h>
#include <stdarg.h>
void myfunc(char* fmt, ...);
/* this example folows logic of printf to specify format
%d - integer
%c - single character
%s - string
other character will be copied to output
*/
int main( int argc, char* argv[])
{
myfunc("%s %d ABCD %c", "a string", 4, 'D');
}
void myfunc(char *fmt, ...)
{
va_list ap;
int d;
char c, *s;
va_start(ap, fmt);
while (*fmt)
{
if(*fmt == '%')
{
fmt++;
switch (*fmt) // detect format characters
{
case 's': /* string format character is recognized*/
s = va_arg(ap, char *);
printf("string: %s\n", s); /* this example just print out paramater, you can do what you want */
break;
case 'd': /* integer format character */
d = va_arg(ap, int);
printf("int: %d\n", d);
break;
case 'c': /* char format character*/
c = (char) va_arg(ap, int);
printf("char: %c\n", c);
break;
default:
printf("Just copy non format characters %c\n",*fmt); // copy non format characters after %
}
}
else
printf("just copy '%c'\n", *fmt);
fmt++;
}
va_end(ap);
}