使用<stdarg.h>
标头,可以创建一个具有可变参数数量的函数,但是:
-
要开始使用
va_list
,您需要使用一个va_start
宏,该宏需要知道那里有多少参数,但是printf
和...使用va_list
不需要参数计数。如何创建一个不需要像printf
那样的参数计数的函数? -
假设我想创建一个接受
va_list
的函数,而不是使用它,而是将其传递给另一个需要va_list
的函数?(所以在伪代码中,它会像void printfRipOff(const char* format, ...) {printf(format, ...);}
)
假设我想创建一个接受va_list
的函数,而不是使用它,而是将其传递给另一个需要va_list
的函数?
查看函数vprintf( const char * format, va_list arg );
,了解将va_list
作为输入参数的函数示例。
它基本上是这样使用的:
#include <stdio.h>
#include <stdarg.h>
void CountingPrintf(const char* format, ...)
{
static int counter = 1;
printf("Line # %d: ", counter++); // Print a Counter up front
va_list args;
va_start(args, format); // Get the args
vprintf(format, args); // Pass the "args" through to another printf function.
va_end(args);
}
int main(void) {
CountingPrintf("%s %sn", "Hello", "World");
CountingPrintf("%d + %d == %dn", 2, 3, 2+3);
return 0;
}
输出:
Line # 1: Hello World
Line # 2: 2 + 3 == 5
-
像
printf()
和scanf()
这样的函数具有格式字符串参数,该参数告诉它们函数调用必须提供的参数的数量和类型。如果你正在编写自己的函数,你必须有某种方法来知道提供了多少参数及其类型。 可能是它们都是同一类型。 它们可能都是指针,您可以使用空指针来指示参数的结尾。 否则,您可能必须包括计数。
只要 被调用的函数需要
va_list
,您就可以这样做。 有一些警告(参见 C11 §7.16 变量参数),但只需稍加努力即可管理。
一个非常常见的习语是,你有一个函数int sometask(const char *fmt, ...)
和第二个函数int vsometask(const char *fmt, va_list args)
,你实现第一个函数作为对第二个函数的简单调用:
int sometask(const char *fmt, ...)
{
va_list args;
va_start(fmt, args);
int rc = vsometask(fmt, args);
va_end(args);
return rc;
}
当然,第二个函数执行实际工作,或者调用其他函数来完成实际工作。
在问题中,你说:
。
va_start
需要知道多少参数的宏...
不需要;va_start
宏只需要知道哪个参数是省略号之前的参数 — 函数定义中, ...
之前的参数名称。
在评论中,您说:
这就是我想写的,但它没有用。
string format(const char* text, ...) { // temporary string used for formatting string formattedString; initializeString(&formattedString, text); // start the va_list va_list args; va_start(text, args); // format sprintf(formattedString.array, text, args); // end the va_list va_end(args); return formattedString; }
正如 abelenky 在评论中指出的那样,您需要使用vsprintf()
:
string format(const char* text, ...)
{
string formattedString;
initializeString(&formattedString, text);
va_list args;
va_start(text, args);
vsprintf(formattedString.array, text, args);
va_end(args);
return formattedString;
}
这假定formattedString
在数组中有足够的空间来存储格式化结果。 它是如何组织的并不明显,但大概你知道它是如何工作的,它是如何安全的。 如果可以确定formattedString
中的可用空间,请考虑使用vsnprintf()
。
printf
和scanf
系列函数不需要显式传递va_list
的长度,因为它们能够通过格式字符串推断参数的数量。
例如,在这样的调用中:
printf("%d %c %sn", num, c, "Hello");
printf
能够检查第一个参数,即格式字符串,并看到它包含%d
、%c
和%s
,因此它可以假定有三个附加参数,第一个是signed int
,第二个是char
,第三个是它可能假定是指向以 null 结尾的字符串的指针的char*
。
要编写一个不需要明确告诉正在传递多少参数的类似函数,您必须找到一种方法来巧妙地为它提供一些信息,使其能够推断va_list
中参数的数量和类型。