vprintf 是如何实现的? [英] How is vprintf implemented?

查看:99
本文介绍了vprintf 是如何实现的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果想用 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?

换句话说,vprintfprintf 的本质区别在符合标准的 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_startva_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆