在运行时使用动态参数调用printf

时间:2019-01-25 13:39:05

标签: c++

我尝试用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(")");

3 个答案:

答案 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);
}