不指定参数数量的可变参数函数

时间:2019-11-07 04:07:17

标签: c variadic-functions

我正在研究C编程语言,我发现非常有趣的一件事是可变参数函数的实现。我目前正在尝试打印传递给函数的每个值,但是我只得到一部分参数。

我尝试运行一些在网上找到的示例,这些示例用于获取参数的平均数以及求和算法(如下所示)。

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

int sum(int count, ...)
{
    va_list args;
    va_start(args, count);
    int total = 0;

    for (int i = 0; i < count; i++) {
        int num = va_arg(args, int);
        total += num;
        printf("Value #%d: %d\n", i, num);
    }

    va_end(args);

    return total;
}

int main()
{
    int result = sum(1, 2, 3, 4, 5);
    printf("The result is: %d\n", result);
}

上面的代码仅打印:

Value #0: 2
The result is: 2

我认为这是因为for循环使用第一个参数作为索引的最大值。但是...

我的问题是,printf是如何工作的,如果不需要在格式化字符串中传递大量要替换的参数? 是因为在后台,C运行时计算了格式化字符串中声明了多少个格式说明符?那是我的猜测。

谢谢。

2 个答案:

答案 0 :(得分:3)

无法找出实际上提供了多少个参数。

printf()从格式字符串中找出来。格式字符串中的每个%运算符都对应一个参数(这是一种简化形式),它需要处理的参数数量足以填充每个参数。

所以,如果您写:

printf("%d %s\n", intvar, stringvar);

它知道必须有2个其他参数:一个用于%d,另一个用于%s

某些功能使用的另一种方法是用哨兵值指示最后一个参数。

execl("program", "arg0", "arg1", "arg2", (char *)NULL);

execl()处理参数,直到达到NULL值为止。

答案 1 :(得分:0)

如果您以以下方式调用可变参数函数:

int result = sum(5 /*count*/, 1, 2, 3, 4, 5);

通过添加首字母5(一个计数),它可以实现您期望的效果,但是为了有趣,请尝试使用更大的数字(例如6或10)进行调用,然后看看会发生什么。他们很容易出错。

可变参数函数几乎唯一的好案例是针对您的应用量身定制的printf变体。我长期以来最喜欢的是die(),它使用printf样式的格式字符串(和参数),将其发送到标准错误,追加换行符,然后退出程序。

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

void die(const char *format, ...)
{
    va_list args;

    va_start(args, format);
    vprintf(stderr, format, args);
    va_end(args);
    fprintf(stderr, "\n");

    exit(EXIT_FAILURE);
}

,然后将其放在您的头文件中以供使用:

extern void die(const char *format, ...)
   __attribute__((noexit))         // function never exits
   __attribute__((printf(1, 2)));  // looks like printf, format is arg1

现在您可以调用die("Program failed because %s", reason);,它在程序上运行时没有很多麻烦和烦恼。并且由于使用__attribute__,编译器(至少是GNU)知道如何验证格式字符串的参数。

相关问题