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

我遇到的代码位于伪格式函数中,该函数接受格式字符串和零个或多个参数(const char *format, ...)作为输入。然后,它将处理使用某些参数的某些占位符,并将其余参数与动态生成的新va_list一起传递给vsprintf

这是生成新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 *,所以我得到:

错误:ISO C++禁止转换为数组类型'__va_list_tag [1]'

最佳答案

我有点迷路了。为什么需要一个新的动态生成的va_list?为什么不重用旧的呢?

我相信vsnprintf()使用当前的va_list对象(如果可以调用它的话)。因此,您可以自由使用va_start(),通过va_arg()使用所需的参数,然后将其余参数通过va_list传递给vsnprintf(),然后调用va_end()。

我想念什么吗?为什么要深复制?

而且,如果确实需要深层拷贝,为什么不新鲜va_start(),请通过va_arg()删除所需的参数,然后将生成的va_list对象传递给vsnprintf()。

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

或者,您可以只使用va_copy()。 (尽管一定要在其后跟随相应的va_end()。)

附录:还请注意,这些va_宏基于C89和C99标准。 GNU g++将支持它们。微软的局限性更大。

跟踪,TonyK的评论:

如果您从va_list中拉出前N个项目,我上面所说的有效。如果您要从中间拉出物品,那就很难了。

没有可移植的方法来构造vat列表

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

您也可以使用适当制作的va_list打印出原始格式字符串的小节。换句话说,第一个vsnprintf()调用将打印元素1..3,第二个元素5..7,第三个元素10..13,等等。(因为vsnprintf()会忽略va_list上超出其所需内容的其他元素您只需要一系列相应的format-string-fragments,并根据每个vsnprintf()调用的需要,使用va_arg()从va_list中弹出项目。)

10-05 22:03