vprintf 是如何实现的? [英] How is vprintf implemented?
问题描述
如果想用 C 编写一个函数,将变量参数列表传递给 printf
,则必须使用 vprintf
版本.如何为自定义函数实现这种机制?
If one wants to write a function in C that passes a variable argument list through to printf
one has to use the vprintf
version. How can I implement this mechanism for a custom function?
换句话说,vprintf
与 printf
的本质区别在符合标准的 C 中实现是什么?
In other words, how is the essence of what sets vprintf
apart from printf
implemented in standard conforming C?
推荐答案
如果你想写一个以 va_list
作为参数的函数,vprintf
的方法,那么你就这样做吧.您可以使用 va_arg
以正常方式从 va_list
中提取参数.
If you want to write a function which takes a va_list
as an argument, the way vprintf
does, then you just do that. You can extract arguments from the va_list
with va_arg
in the normal way.
不要在 va_list
上调用 va_start
或 va_end
:这是调用者的责任.由于您无法以正常方式重新启动va_list
,如果您需要多次扫描它,则需要va_copy
它.
Don't call va_start
or va_end
on the va_list
: that's the responsibility of the caller. Since you can't restart the va_list
in the normal way, if you need to scan it more than once, you'll need to va_copy
it.
这是一个简单的示例,仅用于说明(即,它并不意味着是可能的最佳实现).
Here's a quick example, just for illustration (i.e. it's not meant to be the best possible implementation).
这两个函数只是使用提供的分隔符字符串连接一堆字符串.第一个是v"版本(如 vsprintf),它实现了逻辑.第二个是 varargs 版本,它将 va_list 打包并传递给实现.
These two functions just join a bunch of strings using a provided delimiter string. The first one is the "v" version (like vsprintf), which implements the logic. The second one is the varargs version which packages up the va_list and passes it to the implementation.
内部函数两次遍历参数;第一次添加字符串的大小.这两个函数都返回一个新的 malloc 字符串,调用者需要释放该字符串.
The inner function runs through the arguments twice; the first time it adds the sizes of the strings. Both functions return a newly-malloc'd string which will need to be free'd by the caller.
参数列表必须以 NULL
结束.
The argument list must be terminated with a NULL
.
char* vjoin(const char* delim, va_list ap) {
va_list aq;
va_copy(aq, ap);
size_t dlen = strlen(delim);
/* First pass. Use the copied va_list */
size_t needed = 1; /* NUL terminator */
const char* s = va_arg(aq, const char*);
if (s) {
needed += strlen(s);
while ((s = va_arg(aq, const char*)))
needed += dlen + strlen(s);
}
va_end(aq);
/* Second pass. Use the original va_list */
char* rv = malloc(needed);
size_t offset = 0;
*rv = 0;
s = va_arg(ap, const char*);
if (s) {
strcpy(rv, s);
offset = strlen(s);
while ((s = va_arg(ap, const char*))) {
strcpy(rv + offset, delim);
strcpy(rv + offset + dlen, s);
offset += dlen + strlen(s);
}
}
return rv;
}
char* join(const char* delim, ...) {
va_list ap;
va_start(ap, delim);
char* rv = vjoin(delim, ap);
va_end(ap);
return rv;
}
这篇关于vprintf 是如何实现的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!