如何在GCC上创建va_list?

时间:2010-12-26 19:10:26

标签: c++ c gcc code-conversion

我正在尝试转换一些代码,以便它也可以在gcc上编译(现在,它仅在MSVC上编译)。

我坚持的代码是伪格式化函数,它接受一个格式字符串和零个或多个参数(const char *format, ...)作为输入。然后,它将处理一些占位符,消耗某些参数,并将其余部分传递给vsprintf以及动态生成的新va_list。

这是用于生成新va_list

的实际代码
char *new_args = (char *) malloc(sum);
char *n = new_args;

for(int i = 0; i < nArgs; i++)
{
    int j   = order[i];
    int len = _getlen(types[j]);

    memcpy(n, args + cumulOffsets[j], len);
    n += len;
}

vsprintf(buffer, sFormat.c_str(), new_args);

在我的辩护中,我没有,也绝不会写这段代码。事实上,我认为这是我一生中见过的最讨厌的事情之一。

然而,这个功能非常复杂,非常古老,而且非常重要。它也没有被修改多年(好吧,除了现在),所以虽然我想从头开始重写它,但我无法证明它需要的时间加上它会引入的错误。

所以,我需要一种方法在GCC上做同样的事情..但是va_list不是char *所以我得到了:

error: ISO C++ forbids casting to an array type '__va_list_tag [1]'

3 个答案:

答案 0 :(得分:4)

我有点失落。为什么需要 动态生成的 va_list ?为什么不重用旧的呢?

我相信 vsnprintf()使用当前的 va_list 对象(如果可以调用它)。所以你可以自由地 va_start(),通过 va_arg()使用你想要的参数,然后通过 va_list 将剩下的参数传递给< em> vsnprintf(),然后调用 va_end()

我错过了什么吗?为什么要深刻复制?

如果你确实需要深层拷贝,为什么不 va_start(),请通过 va_arg()删除你想要的参数,然后传递结果 va_list 对象 vsnprintf()

(每次调用 va_arg 都会修改 va_list 对象,以便下一个调用返回下一个参数。)

或者,您可以使用 va_copy()。 (尽管一定要跟着对应的 va_end()。)

附录:另请注意,这些va_宏基于C89&amp; C99标准。 GNU g ++将支持它们。微软有点受限制。


跟进 TonyK的 评论:

如果你从 va_list 中拉出前N个项目,我上面所说的是有用的。如果你把物品拉出中间,那就更难了。

构建 a va_list 没有可移植的方法。

但是,您可以拆分格式字符串,使用它来确定对象类型(double,float,int等),并使用它自己的格式字符串(原始格式字符串的子部分)单独打印每个字符串。 。多个 snprintf()调用将导致一些开销。但如果不经常调用这个例程,它应该是可行的。

您还可以使用精心设计的 va_list 打印出原始格式字符串的子部分。换句话说,第一个 vsnprintf()调用打印元素1..3,第二个元素5..7,第三个10..13等等(As vsnprintf()< / em>会忽略 va_list 上的额外元素,超出它的需要。你只需要一系列相应的格式字符串片段,然后用 va_list 弹出项目<每个 vsnprintf()调用需要em> va_arg()。)

答案 1 :(得分:1)

没有足够的上下文来弄清楚你在这里要做什么,但是如果你需要复制一个va_list,你可以使用gg支持的C99标准函数va_copy(但是我不知道MS是否支持它。)

答案 2 :(得分:0)

有一种方法可以做到这一点,它并不漂亮:

union {
      char *pa;
      va_list al;
      } au;

....
au.pa = new_args;
vsprintf(buffer, sFormat.c_str(), au.al);

使用联合而不是强制转换很难看,但如果va_list是数组类型,则无法强制转换。