我想将使用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;
}
答案 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;
}