i具有实现printf
自定义变体的函数。有人知道如何使用va_list
打印出一个更多参数?我的格式就像"%d some text %s"
。我需要a
,以第一个参数印刷。
void func (int a, char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
// vprintf(stdout, fmt, a, ap) //Can't do like this :(
vfprintf(fmt, a, ap); //Or like this :(
va_end(ap);
}
如果始终以相同的方式打印a
,则不应是传递格式的一部分。您应该单独打印。
在您给出的示例中,将格式字符串更改为 "some text %s"
。那么您的功能可以做到这一点:
void func (int a, char *fmt, ...) {
va_list ap;
// first print the function specific fields
printf("%d ", a);
// then the user's format
va_start (ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
如注释中所述:
重新设计接口
您将最好重新设计接口,以便格式字符串仅适用于...
(va_list
)参数;固定的参数分别处理。
想要额外参数的标准原因是记录诸如__FILE__
和__LINE__
之类的内容(如果您没有C99 __VA_ARGS__
支持,则可能不是__func__
,请参见下文)。您可能会尽力删除这些固定参数的呼叫者控制格式的选项,而fmt
仅处理...
参数。
如果您不能重新设计接口
%d
是格式的一部分,int
值不是va_list
的一部分。
如果您不能或拒绝更改调用该功能的规则,则需要解析格式,例如将其分为(但不包括)第二个%
,并使用该格式与独立的论点;然后,格式的其余部分将传递给vprintf()
。如果您正在使用POSIX系统和多线程程序中,则可能需要在Stdout上使用flockfile()
和funlockfile()
,以确保尽管有多线程,但仍将它们视为单个输出单位。
// Using C99 features
void func(int a, char *fmt, ...)
{
char *p1 = strchr(fmt, '%');
if (p1 == 0)
{
// No conversion specifications. Not puts(); it adds a newline
fputs(fmt, stdout);
return;
}
char *p2 = strchr(p1 + 1, '%');
if (p2 == 0)
{
// The user invoked func(1, "iteration %d:n");?
printf(fmt, a);
return;
}
int buflen = p2 - fmt + 1;
char buffer[buflen];
memmove(buffer, fmt, buflen);
buffer[buflen-1] = ' ';
// flockfile(stdout); // Multi-threading
printf(buffer, a);
va_list ap;
va_start(ap, fmt);
vprintf(p2, ap);
va_end(ap);
// funlockfile(stdout); // Multi-threading
}
代码作弊;它使用C99 VLA(可变长度阵列)以及交错的声明和语句。因此,在C90中,您可能最终会使用malloc()
,或者可能使用固定尺寸的缓冲区(运行溢出风险)或混合动力车(如果格式字符串的前缀足够适合或适合,请使用固定尺寸的缓冲区分配(免费)(如果不是))。
您需要决定适当的错误处理策略。请注意,这不是防弹代码。调用func(a, "%% yield is %d; data is [%s]n", data);
在工作中抛出另一个扳手。另外,如果您在Posix上,并且有人通过"它是%2 $ s,并且%1 $ D发生了事情",那么您会遇到深刻的麻烦。
是的,我正在使用Posix系统。但是它很旧,我什至无法使用
__VA_ARGS__
宏的方法,因为它显示在C99 标准中。
很好奇您在这样的旧系统上。但是,这仅意味着您可能不会用其中的n$
表示代码编写代码,因此要担心的是一件事。多线程问题也不太可能成为问题。而且您无法使用我的示例代码中显示的其他C99功能。
您可以查看FFI(外函数接口)库;我根本不确定它会有所帮助。
基于对解析格式的先前答案,我找到了一个简单的解决方案(如果%d
始终是首先):
void func (int a, char *fmt, ...) {
char *new_format = malloc(10*sizeof(char));
snprintf(new_format, 10, "%d", a);
strcat(new_format, (fmt+2));
va_list ap;
va_start (ap, fmt);
vprintf(stdout, new_format, ap);
va_end(ap);
}
特别感谢Jonathan Leffler