C 编程中可变数量的参数

Variable number of arguments in C programmng

每当我们在C语言中使用可变参数函数时,我们都必须提供参数总数作为第一个参数。有没有什么方法可以在不给出参数总数的情况下创建一个带有可变参数的函数?


[更新自 :]

我想使用像 sum(1,2,3) 这样的函数应该 return 6。也就是说,那里不应该有计数器。

您不必提供那么多参数。例如,考虑 printf:

的签名
int printf( const char* format, ... );

它"finds out" 通过解析你给它的字符串需要多少个参数。当然,您的函数需要以 some 方式知道参数的数量,否则它采用可变数量的参数有什么意义?

几种方式:

  • 通过简单、明确的计数(您在本题中不需要)
  • 传递一些格式字符串,类似于 printf 和 scanf
  • 传递一些 "mode" 参数,并让每个模式都需要特定的可变参数
  • 所有可变参数都是同一类型,并要求最后一个参数是一些特殊值,又名标记值,例如指针列表为 NULL 或 max/min整数类型的类型值,或双精度的 NaN。

无论你怎么做,你都必须有一些方法让函数知道可变参数的类型,以及让它知道它们何时结束的方法。 C中没有内置方法,参数计数不会传递给函数。

I want to use functions like sum(1,2,3) should return 6. i.e, no counter should be there

你可以定义一个哨兵。在这种情况下 0 可能有意义。

/* Sums up as many int as required. 
   Stops adding when seeing the 1st 0. */
int sum(int i, ...)
{
  int s = i;

  if (s)
  {
    va_list ap;

    va_start(ap, i); 

    /* Pull the next int from the parameter list and if it is
       equal 0 leave the while-loop: */
    while ((i = va_arg(ap, int))) 
    {
      s += i;
    }

    va_end(ap);
  }

  return s;
}

这样称呼它:

int sum(int i, ...);

int main(void)
{
   int s = sum(0); /* Gives 0. */

   s = sum(1, 2, 3, 0); /* Gives 6. */
   s = sum(-2, -1, 1, 2, 0); /* Gives 0. */
   s = sum(1, 2, 3, 0, 4, 5, 6); /* Gives 6. */

   s = sum(42); /* Gives undefined behaviour! */
}

sum() 函数也可以看起来像这样(但会做一个 useless 添加 0):

/* Sums up as many int as required. 
   Stops adding when seeing the 1st 0. */
int sum(int i, ...)
{
  int s = i;

  if (s)
  {
    va_list ap;

    va_start(ap, i); 

    /* Pull the next int from the parameter list and if it is
       equal 0 leave the do-loop: */
    do
    {
      i = va_arg(ap, int);
      s += i;
    } while (i);

    va_end(ap);
  }

  return s;
}

可以创建一个将计数作为第一个参数的可变参数函数,然后使用可变参数宏自动添加计数值:

#include <stdarg.h>

#define count_inner(a1, a2, a3, a4, a5, num, ...)  (num)
#define count(...)                                 count_inner(__VA_ARGS__, 5, 4, 3, 2, 1)
#define sum(...)                                   sum_func(count(__VA_ARGS__), __VA_ARGS__)

int sum_func(int count, ...)
{
    va_list ap;
    va_start(ap, count); 

    int total = 0;
    while(count--)
        total += va_arg(ap, int);

    va_end(ap);

    return total;
}

使用 sum 宏而不是 sum_func 允许省略计数,前提是有 1 到 5 个参数。更多 arguments/numbers 可以根据需要添加到 count_inner/count 宏。

int main(void)
{
    printf("%d\n", sum(1));
    printf("%d\n", sum(1, 2));
    printf("%d\n", sum(1, 2, 3));
    printf("%d\n", sum(1, 2, 3, 4));
}

输出:

1
3
6
10

好吧,问题是您必须向函数指示您的参数列表已用尽。你有一个来自 printf(3) 的方法,你可以在你的第一个参数中表达参数的顺序和类型(强制为字符串参数)你可以在第一个参数中表达它,或者,对于添加,因为值 0 实际上并没有添加到总和中,您可以使用该值(或您的标准中的其他值)来表示最后一个参数。例如:

int sum(int a0, ...)
{
    int retval = a0;
    va_list p;
    va_start(p, a0);
    int nxt;
    while ((nxt = va_arg(p, int)) != 0) {
        retval += nxt;
    }
    return retval;
}

这样,你就不必把参数的个数作为第一个参数,你可以简单地:

total = sum(1,2,3,4,5,6,7,8,9,10,0);

但在这种情况下你必须小心,你永远不会有一个等于零的中间参数。或者您也可以使用引用,在您的引用不是 NULL 时添加,如:

int sum(int *a0, ...)
{
    int retval = *a0;
    va_list p;
    va_start(p, a0);
    int *nxt;
    while ((nxt = va_arg(p, int*)) != NULL) {
        retval += *nxt;
    }
    return retval;
}

你可以拥有:

int a, b, c, d, e, f;
...
int total = sum(&a, &b, &c, &d, &e, &f, NULL);