我正在研究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运行时计算了格式化字符串中声明了多少个格式说明符?那是我的猜测。
提前感谢。
无法找出实际上提供了多少个参数。
printf()
从格式字符串中找出来。格式字符串中的每个%
运算符都对应一个参数(这是一种简化形式),它需要处理的参数数量足以填充每个参数。
所以,如果你写:
printf("%d %s\n", intvar, stringvar);
它知道必须有2个其他参数:一个用于%d
,另一个用于%s
。
某些功能使用的另一种方法是用哨兵值指示最后一个参数。
execl("program", "arg0", "arg1", "arg2", (char *)NULL);
[execl()
]处理参数,直到达到NULL
值。
如果您将可变参数函数称为:
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)知道如何验证格式字符串的参数。