How is vprintf implemented? [duplicate]

╄→гoц情女王★ 提交于 2019-12-13 17:47:57

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!