C++ 相当于 sprintf?
Posted
技术标签:
【中文标题】C++ 相当于 sprintf?【英文标题】:C++ equivalent of sprintf? 【发布时间】:2011-02-13 07:50:54 【问题描述】:我知道std::cout
是printf
的 C++ 等价物。
sprintf
的 C++ 等价物是什么?
【问题讨论】:
【参考方案1】:std::ostringstream
例子:
#include <iostream>
#include <sstream> // for ostringstream
#include <string>
int main()
std::string name = "nemo";
int age = 1000;
std::ostringstream out;
out << "name: " << name << ", age: " << age;
std::cout << out.str() << '\n';
return 0;
输出:
name: nemo, age: 1000
【讨论】:
我认为 sprintf 不会写入标准输出。我会删除上面的插入语句。 这与sprintf (...)
有何相似之处?您不能任意格式化数据,当您使用 <<
运算符将数据输入流时,您必须依赖已知的类型。
我需要同意@AndonM.Coleman 关于这一点。这并不是真正的 sprintf 替代品。 This 会更像这样,但这是 Qt。
正如@vinkris 在他的回答中所说,iomanip 实现了格式化。我会说“result = out.str()”,而不是打印到 stdoit。
sprintf / snprintf 允许格式化和打印到用户分配的字符数组,可能在堆栈上。在 snprintf() 的情况下,它确保没有溢出。这里我们多次分配内存,调用者无法直接访问它。必须转换为字符串才能获得输出。带有自定义 std::streambuf 的 std::ostream 会更好地匹配用户缓冲区 - 当然,ostream/streambuf 的构造/销毁会增加效率。【参考方案2】:
2019 年 8 月更新:
看起来 C++20 会有std::format
。参考实现是fmt。如果您现在正在寻找printf()
替代方案,这将成为新的“标准”方法,值得考虑。
原文:
使用Boost.Format。它具有类似printf
的语法、类型安全、std::string
结果以及许多其他漂亮的东西。你不会回去的。
【讨论】:
...除非您担心可执行文件的大小.. :P 这会产生多大的影响? Boost 依赖项仅是标头,没有链接,对吗? @KenWilliams 是的,Boost.Format 只是标题。我的 Mac 上的一个简单的“hello, world”测试从 10kB 增加到 78kB。在实际项目中,额外的大小将在编译单元之间分摊(提供正确的链接器选项),并且类型安全带来其他好处。 当可执行文件大小膨胀时,总是尝试使用共享库!【参考方案3】:sprintf 在 C++ 中工作得很好。
【讨论】:
我认为 OP 的意思是 STL 而不是 C++。 sprintf 要求您分配字符缓冲区。我想要类似“std::string”的“append”方法,它允许我添加格式化数据,并在幕后处理分配。【参考方案4】:这是一个很好的 c++ sprintf 函数。如果过度使用 Streams,它们会变得很丑。
std::string string_format(const std::string &fmt, ...)
int size=100;
std::string str;
va_list ap;
while (1)
str.resize(size);
va_start(ap, fmt);
int n = vsnprintf(&str[0], size, fmt.c_str(), ap);
va_end(ap);
if (n > -1 && n < size)
str.resize(n); // Make sure there are no trailing zero char
return str;
if (n > -1)
size = n + 1;
else
size *= 2;
在 C++11 及更高版本中,std::string 保证使用以'\0'
结尾的连续存储,因此使用&str[0]
将其转换为char *
是合法的。
已经指出,可变参数不应该遵循传递引用,并且 c++ 最好不要复制字符串,如果它不需要的话。在这种情况下,这可以解决它。
std::string string_format(std::string fmt, ...)
【讨论】:
非常好的解决方案!我在这里对其进行了调整:***.com/a/3742999/15161 以更贴合sprintf
-usage。
非法,但:(char*) str.c_str()
抛弃了const
。
还有潜伏的缓冲区溢出问题
@MSalters 正确。在 C++11 中有一种合法的方式来做到这一点。
@whitequark:随意添加它作为答案。在 Stack Overflow 上,好的问题仍然存在,以允许新的答案。【参考方案5】:
您可以使用iomanip 头文件来格式化输出流。 检查this!
【讨论】:
为什么有人反对这个? iomanip 不是在流中实现格式化的纯 C++ 方式吗?我认为这里的目标是避免将数据存储在 C 风格的字符串中,这是通过 iomanip 实现的。【参考方案6】:根据您对sprintf()
ing 的具体计划,std::to_string()
可能比其他选项更有用且更惯用:
void say(const std::string& message)
// ...
int main()
say(std::to_string(5));
say("Which is to say " + std::to_string(5) + " words");
std::to_string()
(恕我直言)的主要优点是它可以轻松扩展以支持 sprintf()
甚至无法实现字符串化的其他类型 - 有点像 Java 的 Object.toString()
方法。
【讨论】:
【参考方案7】:使用字符串流来达到同样的效果。此外,您可以包含 <cstdio>
并仍然使用 snprintf。
【讨论】:
以上是关于C++ 相当于 sprintf?的主要内容,如果未能解决你的问题,请参考以下文章
带有 unsigned long long 和 sprintf 的 Visual C++ 6.0