Q我如何编写一个接受可变数量参数并将其传递给另一个函数(该函数也接受可变数量参数)的函数?
A一般来说,你不能。理想情况下,你应该提供该其他函数的一个版本,该版本接受一个va_list指针,会发生什么。
假设您想编写一个faterror函数,该函数将打印一个致命错误消息,然后退出。您可能希望将其写成基于函数(来自第 15.5 题)的一个版本,使用了问题 15.5 的函数
void faterror(const char *fmt, ...) { error(fmt, what goes here? ); exit(EXIT_FAILURE); }但如何处理尚不清楚faterror的参数传递给函数(来自第 15.5 题)的一个版本,使用了.
执行以下操作。首先,拆分现有的函数(来自第 15.5 题)的一个版本,使用了函数以创建一个新的verror该函数不接受可变参数列表,而是接受一个单独的va_list指针。 (请注意,这样做只是做了很少的额外工作,因为verror包含了很多以前在函数(来自第 15.5 题)的一个版本,使用了中使用的代码,而新的函数(来自第 15.5 题)的一个版本,使用了成为一个简单的包装器,围绕着verror.)
#include <stdio.h> #include <stdarg.h> void verror(const char *fmt, va_list argp) { fprintf(stderr, "error: "); vfprintf(stderr, fmt, argp); fprintf(stderr, "\n"); } void error(const char *fmt, ...) { va_list argp; va_start(argp, fmt); verror(fmt, argp); va_end(argp); }
现在你可以写faterror,并让它调用verror,也可以
#include <stdlib.h> void faterror(const char *fmt, ...) { va_list argp; va_start(argp, fmt); verror(fmt, argp); va_end(argp); exit(EXIT_FAILURE); }请注意,之间的关系函数(来自第 15.5 题)的一个版本,使用了和verror正是 e.g. 之间的关系printf和vprintf。事实上,正如 Chris Torek 所观察到的,每当您发现自己编写一个 varargs 函数时,最好编写它的两个版本:一个(如verror)接受一个va_list并完成工作,另一个(如修改后的函数(来自第 15.5 题)的一个版本,使用了)是一个简单的包装器。唯一的真正限制是,像verror这样的函数只能扫描一次参数;无法重新调用 va_start。
如果您没有选择重写较低级别的函数(函数(来自第 15.5 题)的一个版本,使用了在此示例中)以接受一个va_list,因此您发现自己需要将一个函数(例如faterror)接收到的可变参数传递给另一个作为实际参数,则不可能有可移植的解决方案。 (问题也许可以通过诉诸机器特定的汇编语言来解决;另请参阅问题 15.13。)
一种不会起作用的方法是这样的
void faterror(const char *fmt, ...) { va_list argp; va_start(argp, fmt); error(fmt, argp); /* WRONG */ va_end(argp); exit(EXIT_FAILURE); }Ava_list本身并不是一个可变参数列表;它实际上是一种指向它的指针。也就是说,一个接受va_list的函数本身不是 varargs,反之亦然。
另一种有时被使用,并且有时有效但严重不便携的解决方法是使用大量的int参数,希望有足够的参数,并且它们能够以某种方式传递指针、浮点和其他参数
void faterror(fmt, a1, a2, a3, a4, a5, a6) char *fmt; int a1, a2, a3, a4, a5, a6; { error(fmt, a1, a2, a3, a4, a5, a6); /* VERY WRONG */ exit(EXIT_FAILURE); }此示例仅用于劝您不要使用它;请不要仅仅因为在这里看到它就尝试。