问题
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?
In other words, how is the essence of what sets vprintf
apart from printf
implemented in standard conforming C?
回答1:
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.
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).
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.
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.
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;
}
回答2:
The trick is to realize that vprintf
(or more likely vfprintf
) is the underlying core function that's implemented. printf
is likely to be just a wrapper that calls va_start
, vprintf
, then va_end
.
回答3:
The big difference is, of course, that printf
takes a variable number of optional arguments after the format string, while vprintf
takes a single non-optional argument that "points" to all arguments.
Most implementations of printf
creates this single data structure and in turn calls vprintf
.
Read any tutorial about variable number of arguments (also known as variadic arguments) to see how it works. This printf (and family) reference might also come in handy, as well as this variable arguments reference (which has an example).
来源:https://stackoverflow.com/questions/26918450/how-is-vprintf-implemented