使用printf样式格式设置std :: string的内容

时间:2013-11-30 14:28:41

标签: c++ printf stdstring

我想将使用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, '\0');
    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: %d\ncontents: %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;
}

3 个答案:

答案 0 :(得分:3)

只需使用operator[](即&str[0])代替c_str()。那么没有未定义的行为。

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

完成后你应该砍掉空终结符,因为std::string不需要它。

str.pop_back();

答案 1 :(得分:2)

捕获在这里;

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

阅读C++11 draft spec; (在其他C ++版本中似乎相似)

  

21.4.7.1 basic_string访问者[string.accessors]
     const charT * c_str()const noexcept;
     const charT * data()const noexcept;
     ...
     3要求:程序不得更改存储在字符数组中的任何值

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

答案 2 :(得分:0)

您拥有的代码是错误的,因为它会调用未定义的行为。你是sprintf() - 指向string::c_str()返回的指针。但string::c_str()会返回指向const char的指针,因此您无法执行此操作。为什么不使用非const 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;
}