【发布时间】:2023-12-05 10:15:01
【问题描述】:
A previous question 展示了一种打印到字符串的好方法。答案涉及 va_copy:
std::string format (const char *fmt, ...);
{
va_list ap;
va_start (ap, fmt);
std::string buf = vformat (fmt, ap);
va_end (ap);
return buf;
}
std::string vformat (const char *fmt, va_list ap)
{
// Allocate a buffer on the stack that's big enough for us almost
// all the time.
s ize_t size = 1024;
char buf[size];
// Try to vsnprintf into our buffer.
va_list apcopy;
va_copy (apcopy, ap);
int needed = vsnprintf (&buf[0], size, fmt, ap);
if (needed <= size) {
// It fit fine the first time, we're done.
return std::string (&buf[0]);
} else {
// vsnprintf reported that it wanted to write more characters
// than we allotted. So do a malloc of the right size and try again.
// This doesn't happen very often if we chose our initial size
// well.
std::vector <char> buf;
size = needed;
buf.resize (size);
needed = vsnprintf (&buf[0], size, fmt, apcopy);
return std::string (&buf[0]);
}
}
我遇到的问题是上面的代码没有移植到 Visual C++,因为它没有提供 va_copy(甚至 __va_copy)。那么,有谁知道如何安全地移植上述代码?据推测,我需要做一个 va_copy 复制,因为 vsnprintf 破坏性地修改了传递的 va_list。
【问题讨论】:
-
我已经在 VC++ 中实现了类似的东西,并且从来不需要使用
va_copy()。如果你不使用副本尝试它会发生什么? -
谁知道...它可能看起来有效。即使是这样,也并不意味着它是安全的。
-
显然 va_copy() 是 C99 的东西。对于 VC++,您可以多次使用原始 va_list,而不必担心副本。 vsnprintf 不会尝试修改传递的列表。
-
实际上,不使用 va_copy 复制它是可以的,因为 Visual C++ 中的 va_list 只是指向下一个参数的指针,调用 vsnprintf 不能修改调用者的值。但是,从技术上讲,第一次调用后 ap 的值是不确定的,所以你不应该在第二次调用时使用它。
-
这里还值得一提的是,如果缓冲区不够大用于输出,Microsoft 的 vsnprintf 实现会返回 -1,但有一个例外:如果 NULL 不适合,它会给你返回填充的缓冲区和写入的字符数(显然,也许)没有NULL。 (我不确定如何通过 MS API 获得所需的缓冲区大小;eastl 只是迭代地寻找它。)
标签: c++ c visual-studio-2008 visual-c++