使用printf样式格式设置std::string的内容 我想把文本格式设置为一个C++字符串中的Prtf格式格式化字符串。我想出了下面的方法,这似乎很有效,但我还没有发现其他人承认使用过类似的技术,所以我想我会问为什么我不应该这样做 #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; } #包括 #包括 #包括 void stringprintf(std::string&str,char const*fmt,…){ va_列表ap; va_启动(ap、fmt); 大小n=vsnprintf(NULL,0,fmt,ap); str.resize(n+1,'\0'); char*pStr=(char*)(str.c_str()); (无效)vsnprintf(pStr,str.capacity(),fmt,ap); va_端(ap); } 无效转储字符串(std::string和str){ printf(“对象:%08X,缓冲区:%08X,大小:%d,容量:%d\n内容:%s==\n”, &str,str.c_str(),str.size(),str.capacity(),str.c_str()); } int main(int argc,字符**argv){ std::字符串str; 转储字符串(str); stringprintf(str,“一种测试格式。一个数字%d,一个字符串%s!\n”,12345,“abcdefg”); printf(“%s”,str.c_str()); 转储字符串(str); 返回0; }

使用printf样式格式设置std::string的内容 我想把文本格式设置为一个C++字符串中的Prtf格式格式化字符串。我想出了下面的方法,这似乎很有效,但我还没有发现其他人承认使用过类似的技术,所以我想我会问为什么我不应该这样做 #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; } #包括 #包括 #包括 void stringprintf(std::string&str,char const*fmt,…){ va_列表ap; va_启动(ap、fmt); 大小n=vsnprintf(NULL,0,fmt,ap); str.resize(n+1,'\0'); char*pStr=(char*)(str.c_str()); (无效)vsnprintf(pStr,str.capacity(),fmt,ap); va_端(ap); } 无效转储字符串(std::string和str){ printf(“对象:%08X,缓冲区:%08X,大小:%d,容量:%d\n内容:%s==\n”, &str,str.c_str(),str.size(),str.capacity(),str.c_str()); } int main(int argc,字符**argv){ std::字符串str; 转储字符串(str); stringprintf(str,“一种测试格式。一个数字%d,一个字符串%s!\n”,12345,“abcdefg”); printf(“%s”,str.c_str()); 转储字符串(str); 返回0; },c++,printf,stdstring,C++,Printf,Stdstring,捕获物在这里 char *pStr = (char *)(str.c_str()); (void)vsnprintf(pStr, str.capacity(), fmt, ap); 阅读文章;(在其他C++修订中似乎类似) 21.4.7.1基本字符串访问器[字符串访问器] 常量图表*c_str()常量无异常 常量图表*数据()常量noexcept … 3要求:程序不得更改字符数组中存储的任何值 据我所知,分配内存并创建新字符串/从缓冲区分配它是最接近您的选择。关键就在这里 char *pStr

捕获物在这里

char *pStr = (char *)(str.c_str());
(void)vsnprintf(pStr, str.capacity(), fmt, ap);
阅读文章;(在其他C++修订中似乎类似)

21.4.7.1基本字符串访问器[字符串访问器]
常量图表*c_str()常量无异常
常量图表*数据()常量noexcept

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

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

关键就在这里

char *pStr = (char *)(str.c_str());
(void)vsnprintf(pStr, str.capacity(), fmt, ap);
阅读文章;(在其他C++修订中似乎类似)

21.4.7.1基本字符串访问器[字符串访问器]
常量图表*c_str()常量无异常
常量图表*数据()常量noexcept

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


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

您的代码是错误的,因为它调用了未定义的行为。您正在
sprintf()
-ing到
string::c_str()
返回的指针上。但是
string::c_str()
返回一个指向
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;
}

您的代码是错误的,因为它调用了未定义的行为。您正在
sprintf()
-ing到
string::c_str()
返回的指针上。但是
string::c_str()
返回一个指向
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;
}

只需使用
操作符[]
(即
&str[0]
)而不是
c\u str()
。没有未定义的行为

vsnprintf(&str[0], str.capacity(), fmt, ap);
完成后,您可能应该切掉空终止符,因为
std::string
不需要它

str.pop_back();

只需使用
操作符[]
(即
&str[0]
)而不是
c\u str()
。没有未定义的行为

vsnprintf(&str[0], str.capacity(), fmt, ap);
完成后,您可能应该切掉空终止符,因为
std::string
不需要它

str.pop_back();

此问题似乎是离题的,因为它属于此问题似乎是离题的,因为它属于“谢谢”。我忘记了string类重写了数组索引操作符。然而,在我的测试程序中,至少,&(str[0])返回与str.c_str()相同的值,因此这两种形式看起来是等价的。由于c_str()似乎返回一个指向内部缓冲区的指针,我认为您对终止NUL的看法是错误的,但在某些情况下,可能会为c_str()创建一个新的、以NUL终止的缓冲区。无论如何,我不想做任何像查看库源代码那样不分体的事情来破坏一个好的参数,所以我会把它放在我的巡航导弹制导包里,如果客户投诉,我会进一步调查。由于数组方法不涉及用强制转换蒙蔽编译器,我总是可以责怪库编写器留下了不安全的漏洞。@ChrisBarry:
std::string
在实际字符串字符后保留了一个额外的空终止符。当您使用
vsnprintf
时,它会在字符串中写入空终止符。因此,通过不删除空终止符,您有两个,并且
str.size()
将是
strlen(str.c_str())+1
。是的,我明白了。你说得很对。因此,我的代码将终止字符串后面的NUL字符。我要马上纠正这种挥霍行为。啊!这是一个不可靠的键盘。老实说,谢谢你。我忘记了string类重写了数组索引操作符。然而,在我的测试程序中,至少,&(str[0])返回与str.c_str()相同的值,因此这两种形式看起来是等价的。由于c_str()似乎返回一个指向内部缓冲区的指针,我认为您对终止NUL的看法是错误的,但在某些情况下,可能会为c_str()创建一个新的、以NUL终止的缓冲区。无论如何,我不想做任何像查看库源代码那样不分体的事情来破坏一个好的参数,所以我会把它放在我的巡航导弹制导包里,如果客户投诉,我会进一步调查。由于数组方法不涉及用强制转换蒙蔽编译器,我总是可以责怪库编写器留下了不安全的漏洞。@ChrisBarry:
std::string
在实际字符串字符后保留了一个额外的空终止符。当您使用
vsnprintf
时,它会在字符串中写入空终止符。因此,通过不删除空终止符,您有两个,并且
str.size()
将是
strlen(str.c_str())+1
。是的,我明白了。你真是太棒了