【问题标题】:Variable parameter function with minimum parameter [duplicate]具有最小参数的可变参数函数
【发布时间】:2012-12-19 00:58:50
【问题描述】:

可能的重复:
C++ preprocessor __VA_ARGS__ number of arguments
How to count the number of arguments passed to a function that accepts a variable number of arguments?

为了学习变参函数,我写了一个demo:

#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>

int foo(int n, int m, ...);

int
main (int argc, char *argv[])
{
    int n = 10;
    int m = 15;
    int p = 20;
    //foo (n, m);
    foo(n, m, 20);

    return EXIT_SUCCESS;
}

int foo (int n, int m, ...)
{
    va_list ap;
    int p;
    char *str;

    va_start (ap, m);
    p = va_arg (ap, int);
    n = m + p;
    printf ("%d.\n", n);
    va_end (ap);
    return 0;
}

如果函数只有两个参数,我想知道如何处理它。 (对于这个演示,如果只有nm,在运行foo之后,我想得到结果:n = n+m。)

【问题讨论】:

  • @RedX:那个骗子是针对可变参数宏,而不是可变参数函数。

标签: c parameters


【解决方案1】:

在运行时,无法从 va_list 中获知附加参数的实际数量。因此应该有另一种方法来推断这个数字,例如来自先前的参数或来自某些列表末尾的约定(例如,给出任意数量的指针,后跟 NULL)。考虑printf,其中格式字符串决定了 va_list 部分中期望有多少参数(什么类型)。

只要考虑到这一点,最小参数数量(即空 va_list)就没有什么特别之处。当你知道没什么可期待的时候,不要从 va_list 中弹出任何东西。

【讨论】:

    【解决方案2】:

    对于每个可变参数('variadic')函数,必须有一种方法让函数知道它必须处理多少个参数。有多种处理方法。

    • printf()scanf() 系列函数使用格式字符串来确定传递给函数的参数数量。
    • POSIX open() 函数查看第二个参数中的选项以了解是否存在第三个参数。
    • POSIX execl() 函数进行扫描,直到遇到空指针参数。
    • 您可以传递要处理的参数数量的显式计数(请参阅 Fei Jiangexample)。

    所有这些方法都有效。 open() 机制是最不通用和最奇特的(主要源于历史怪癖)。

    但是必须使用一种这样的机制。被调用的函数必须能够(以某种方式)告诉它何时完成处理其参数列表的变量部分。

    除非您将可变长度参数列表传递给其他函数(例如,您使用vsnprintf() 格式化字符串,并将变量参数传递给函数),否则您的可变参数函数体将需要一个循环来处理变量参数的数量。您的函数缺少该循环。

    【讨论】:

      【解决方案3】:

      我不明白你想让 'foo' 做什么,但通常 foo 应该在其中有一个循环,并且应该告诉 foo 有多少参数在调用时给出,或者更确切地说,在循环结束时给出。 printf 在第一个 char* 模式参数中通过 %d %s %f ... 知道这一点

      比如我们要写一个返回几个整数之和的函数,我们可以这样实现

      #include <stdio.h>
      #include <stdarg.h>
      
      int int_sum(int count, ...) {
          int sum = 0, i;
          va_list ap;
          va_start(ap, count);
          for (i = 0; i < count; ++i) {
              sum += va_arg(ap, int);
          }
          va_end(ap);
          return sum;
      }
      
      int main() {
          printf("%d\n", int_sum(5, 1, 2, 3, 4, 5));
          return 0;
      }
      

      【讨论】:

      • +1:关于循环的必要性很好!计算要处理的参数数量是确定传递给函数的参数数量的多种可能技术之一。
      • 我想写一个这样的节点插入函数:node_insert (list, new), node_insert (list, new_elem, pos) 如果是2个arg,它会从header插入节点,如果它带有3个arg,它将在节点的elem == pos的位置插入节点。
      • @VincentZhang 在这种情况下使用变参函数是不合适的。
      • @Fei Jing:C新手,只是为了锻炼。应该是什么方法?
      • @VincentZhang 这两者之间的唯一区别是,当调用 3-para 时,调用者在运行时堆栈上的 new_elem 之前推送另一个整数(即 pos),但您无法分辨new_elem 上的整数是 node_insert 的第三个参数或调用者的局部变量。我能想出的唯一方法是,添加额外的信息,即另一个参数表明你真正调用哪种形式,但显然,这是一个糟糕的设计
      【解决方案4】:

      我不确定我是否理解了这个问题,但如果您在 varlist 函数中只有一个参数,例如foo(int n,...),然后是...,那么你可以在va_start()中传递foo(在我们的例子中是n)的第一个参数,它总是可以工作的。

      int foo (int n,  ...);
      int
      main (int argc, char *argv[])
      {
          int n = 10;
          int m = 15;
          int p = 20;
      
          foo (n, m);
          //foo (n, m, 20);
      
          return EXIT_SUCCESS;
      }
      
      int foo (int n,  ...)
      {
          va_list ap;
          int p;
          char *str;
      
          va_start (ap, n);
          p = va_arg (ap, int);
          n = n + p;
          printf ("%d.\n", n);
          va_end (ap);
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-24
        • 2019-06-04
        • 2018-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多