使用printf样式的格式设置std::字符串的内容

Using printf-style formatting to set the contents of a std::string

本文关键字:字符串 std 设置 printf 样式 格式 使用      更新时间:2023-10-16

我想把用printf类型格式化字符串格式化的文本放在C++字符串中。我想出了下面的方法,看起来很有效,但我还没有发现其他人承认使用了类似的技术,所以我想我会问为什么我不应该这样做。

#include <stdio.h>
#include <stdarg.h>
#include <string>
void stringprintf(std::string &str, char const *fmt, ...) {
    va_list    ap;
    va_start(ap, fmt);
    size_t n = vsnprintf(NULL, 0, fmt, ap);
    str.resize(n + 1, '');
    char *pStr = (char *)(str.c_str());
    (void)vsnprintf(pStr, str.capacity(), fmt, ap);
    va_end(ap);
}
void dumpstring(std::string &str) {
    printf("Object: %08X, buffer: %08X, size: %d, capacity: %dncontents: %s==n", 
        &str, str.c_str(), str.size(), str.capacity(), str.c_str());
}
int main(int argc, char **argv) {
    std::string str;
    dumpstring(str);
    stringprintf(str, "A test format. A number %d, a string %s!n", 12345, "abcdefg");
    printf("%s", str.c_str());
    dumpstring(str);
    return 0;
}

只需使用operator[](即&str[0])而不是c_str()。没有未定义的行为。

vsnprintf(&str[0], str.capacity(), fmt, ap);

完成后,您可能应该剪掉空终止符,因为std::string不需要它

str.pop_back();

陷阱就在这里;

char *pStr = (char *)(str.c_str());
(void)vsnprintf(pStr, str.capacity(), fmt, ap);

阅读C++11规范草案;(在其他C++版本中似乎相似)

21.4.7.1 basic_string访问者[string.accessors]
const charT*c_str()const noexcept
const charT*data()const noexcept

3要求:程序不得更改字符数组中存储的任何值

据我所知,分配内存并创建一个新字符串/从缓冲区分配它是最接近的选择。

您的代码是错误的,因为它调用了未定义的行为。您正在sprintf()上单击string::c_str()返回的指针。但是string::c_str()返回一个指向const char的指针,所以您不能这样做。为什么不使用非常量char缓冲区并从中构造字符串

int string_printf(std::string &str, const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    int n = std::vsnprintf(NULL, fmt, args);
    va_end(args);
    char *buf = new char[n + 1];
    va_start(args, fmt);
    std::vsnprintf(buf, fmt, args);
    va_end(args);
    str = std::string(buf, n);
    delete[] buf;
    return n;
}