使用va_list格式化C字符串

时间:2015-09-07 15:21:51

标签: c string-formatting

是否有一个等同于snprintf的va_list,其中包含一个变量参数的va_list?我试图实现两个功能:

char * __HYP format_cstring(const char * format, ...);
chat * __HYP format_cstringv(const char * format, var_list args);

但我不确定如何将snprintf应用于这种情况。像这样的东西(注意问号):

char * __HYP format_cstring(const char * format, ...)
{
  int size = snprintf(NULL, 0, format, ??);
  char * buffer = (char *)malloc(size * sizeof(char));

  if (snprintf(buffer, size, format, ??) < 0) {

    free(buffer);
    return NULL;
  }

  return buffer;
}

它的format_cstringv对应物呢?

2 个答案:

答案 0 :(得分:1)

以下是我最终如何做到这一点:

// .h
char * sformat(const char * format, ...) __attribute__((format (printf, 1, 2)));
char * vsformat(const char * format, va_list args) __attribute__((format (printf, 1, 0)));

实施:

char * __HYP sformat(const char * format, ...)
{
  char * buffer;

  va_list args;
  va_start(args, format);
  buffer = __HYP vsformat(format, args);
  va_end(args);

  return buffer;
}

char * __HYP vsformat(const char * format, va_list args)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"

  int size = vsnprintf(NULL, 0, format, args);

  if (size <= 0) {
    return NULL;
  }

  char * buffer = new char[size + 1];

  if (buffer == NULL) {
    return NULL;
  }

  if (vsnprintf(buffer, static_cast<size_t>(size), format, args) <= 0) {

    free(buffer);
    return NULL;
  }

#pragma GCC diagnostic pop

  return buffer;
}

几年后,我一直在发现我对C ++的健忘状况。

答案 1 :(得分:-2)

您对自1980年以来UNOS和DECUS上存在的%r格式感兴趣。

请参阅:http://austingroupbugs.net/view.php?id=800

在libschily中有一个超过30年的实现,请参阅:`http://sourceforge.net/projects/schilytools/files/和尚未发布的实现,作为Solaris上libc的增强。

%r允许任何基于printf()的函数由包装函数调用,然后该函数可以提供完整的printf()特性集。

%r有两个参数:

1)格式字符串

2)va_list类型参数

它需要对名为va_arg_list()的vararg宏进行增强,类似于和出于同样的原因,为什么Sun / Solaris必须在20世纪90年代早期引入va_copy()才能实现%n$

BTW:1985年左右,在usenet上讨论过%r,但当时讨论该功能的人认为它不便携。我的代码已在所有现有的CPU类型上测试过,我有兴趣将其添加到ISO C标准中。

以下是一些示例代码:

int
error(const char *fmt, ...)
{
        va_list args;
        int     ret;

        va_start(args, fmt);
        ret = js_fprintf(stderr, "%r", fmt, args);
        va_end(args);
        return (ret);
}