假设第三方库有一个日志回调,其签名为:
using LogCallback = void (*)(const char* fmt, va_list ap);
并且您需要提供一个回调,将日志消息传递给需要 std::string
的函数:
void PrintLogMessage(const std::string& message);
我假设您需要使用 vsprintf 系列函数之一:
std::string VaList2String(const char* fmt, va_list ap) {
/* ??? something with vnsprintf or vnsprintf_s ??? */
}
void MyLogCallback(const char* fmt, va_list ap) {
std::string message = VaList2String(format, ap);
PrintLogMessage(message);
}
实现上述中与所有主要平台/实现兼容的 VaList2String
的正确(可移植且安全)方法是什么?
最佳答案
void MyLogCallback(const char* fmt, va_list ap) {
std::string message;
va_list ap_copy;
va_copy(ap_copy, ap);
size_t len = vsnprintf(0, 0, fmt, ap_copy);
message.resize(len + 1); // need space for NUL
vsnprintf(&message[0], len + 1,fmt, ap);
message.resize(len); // remove the NUL
PrintLogMessage(message);
}
va_list
通常实际上是一个数组,因此作为参数传入的 ap
实际上是一个指针。我们需要va_copy
来复制指向va_list的指针,这样我们就可以遍历它两次。
请注意,您可能可以在(第一次)调整大小时没有 + 1 ,然后根本不需要第二次调整大小,但从技术上讲,这将是未定义的行为,因为您通过覆盖违反了 std::string 的约束它与另一个 NUL 一起维护的终端 NUL。
关于c++ - 如何将 format/va_list 转换为 std::string? (如何使用 vsnprintf/_s?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70749726/