c++ - 如何将 format/va_list 转换为 std::string? (如何使用 vsnprintf/_s?)

标签 c++ c++17

假设第三方库有一个日志回调,其签名为:

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/

相关文章:

c++ - 以 API 向后兼容的方式添加新的命名空间

c++ - 测试元素是否使用 C++17 折叠表达式排序

c++ - 具有原子状态的单例模式

c++ - std::访问带有重载自由函数而不是函数对象的 std::variant

c++ - 重新组织 vector 的内容

c++ - 如何加快 C++ 链接时间

c++ - QThreads , QObject 和 sleep 函数

c++ - 如何将两个 double 据类型元素转换为一个点数据类型

c++ - 内联函数联动

c++ - 将一个右值的元组转换为一个左值的元组