【问题标题】:How do I fill a va_list如何填写 va_list
【发布时间】:2012-12-04 13:11:50
【问题描述】:

如果我有一个 va_list 我知道如何提取它的所有元素:

void printInts(int n,...)
{
    va_list va;
    va_start(va, n);
    for(unsigned int i=0; i<n; i++)
    {
        int arg=va_arg(va, int);
        printf("%d",arg);
    }
    va_end(va);
} 

所以当我调用 printInts(3,1,2,3) 时,va_list 会填充所有参数。
但是如何在不使用 va_start 的情况下手动填充 va_list?我的意思是我想要类似的东西:

va_list va;
push_arg(va, int, 5); // And so on until I fill all parameters
...

我需要这个,因为有一个函数接受 va_list 作为参数,但我不知道如何填充所有参数的 va_list。

【问题讨论】:

  • va_list 类型实际上并不是一个列表,它实际上通常是一种指向堆栈的指针,va_arg 修改此指针以指向堆栈上的下一个参数.
  • @JoachimPileborg:有时它不是指向堆栈的指针。
  • 你为什么不想使用va_start
  • 因为我需要一个包含所有参数的原始 va_list,所以我需要做与 va_start-va_arg-va_end 相反的事情。

标签: c variadic-functions


【解决方案1】:

无法显式填充 va_list。

你应该写一个包装函数。假设您需要调用函数 foo,而不是手动填写 va_list,而是定义一个新函数,如下所示:

void call_foo(int arg1, ...)
{
   va_list ap;
   va_start(ap, arg1);
   foo(arg1, ap);
   va_end(ap);
}

现在你可以调用foo,它需要一个va_list,但是你喜欢,例如call_foo(1,2,3,4);, call_foo(1, 1, "你好");等等

这将只允许您在编译时指定参数,您不能在运行时构建参数。

【讨论】:

    【解决方案2】:

    通常,这些函数是成对出现的。如果你有一个“va-accepting”功能,很容易再创建一个:

    void printInts_v(int n, va_list ap)
    {
        unsigned int i=0;
        for(i=0; i<n; i++)
        {
            int arg=va_arg(ap, int);
            printf("%d", arg);
        }
    }
    

    这个函数可以这样调用:

    void printInts(int n,...)
    {
        va_list ap;
        va_start(ap, n);
        printInts_v(n, ap);
        va_end(va);
    }
    

    但我认为没有一种方法可以便携地预先填写 va_list 以供以后使用。

    如果您使用一种架构并且可移植性不是问题,那么您可以自己制作一些东西。具体如何做到这一点取决于平台。

    【讨论】:

      【解决方案3】:

      我认为没有标准化的方法可以做到这一点。另一方面,这样一个预填充的va_list 将毫无用处,因为也无法“查询”它以获取可用参数的数量和类型。

      【讨论】:

      • 我认为这个问题类似于“我如何称呼vprintf()?”答案是“写printf() 并从那里调用”。
      • 有一个框架的函数接受一个va_list,我该如何解决这个问题?
      • @RamyAlZuhouri 正如所写 - 到目前为止 - 两个答案。
      • @glglgl:(我知道这是一个很老的问题,但是)这些答案都没有用。因为他们都假设您在编译时知道参数列表。真正的问题是动态构建 va_list。
      • @Camion 这不能做到,至少在便携式标准 C 中不能做到,这就是答案所说的。
      【解决方案4】:

      由于其他回复表明这是不可能的(这将是在下一个版本的语言设计中添加它的一个很好的理由),唯一可移植的可能性是

      • 检查文档两次以调查您是否没有遗漏或 误解了您尝试使用的框架:我 有完全相同的问题here 它出现在答案中 我没有使用正确的调用来做我想做的事情;

      • 为自己编写一个函数,该函数将指针数组作为参数而不是 va_list 并将问题拆分为多个调用(并非总是可能);或

      • 假设您尝试使用的框架设计不佳...

      【讨论】:

        【解决方案5】:

        将函数拆分为多个调用适用于 printf 系列 - 在 Kernighan & Ritchie 中有这样的代码,大致如下:

        void printf_OclFile(struct OclFile* self, char* f, void* sq[])
        { int n = length(sq);
          if (n == 0 || self->actualFile == NULL) 
          { return; }
        
          void* ap; 
          char* p = f; 
          int i = 0; 
        
          char* sval; 
          int ival; 
          double dval; 
        
          ap = sq[0]; 
          for ( ; *p != '\0' && i < n; p++)
          { if (*p != '%')
            { char* p0 = subString(p,1,1); 
              fputs(p0, self->actualFile); 
              continue; 
            } 
        
            p++; /* Points to flag after % */ 
        
            switch (*p)
            { case 'd' : 
                ival = *((int*) sq[i]); 
                i++; 
                fprintf(self->actualFile, "%d", ival);
                break; 
              case 'f' : 
                dval = *((double*) sq[i]); 
                i++; 
                fprintf(self->actualFile, "%f", dval); 
                break; 
              case 's' : 
                sval = ((char*) sq[i]); 
                i++; 
                fprintf(self->actualFile, "%s", sval); 
                break;
              default : 
                char* p0 = subString(p,1,1); 
                fputs(p0, self->actualFile);
                break; 
            }
          } 
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-11-02
          • 2015-05-02
          • 2011-12-02
          • 2021-03-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多