相当于sprintf的C ++?


82

我知道这std::cout与的C ++等效printf

C ++等于sprintf什么?

Answers:


66

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

3
我认为sprintf不会写入stdout。我将删除上面的插入语句。
拉菲·哈查杜安

78
sprintf (...)到底有何相似之处?您不能任意格式化数据,使用<<操作符将其输入流中时,必须依靠已知的类型。
2014年

我需要与@ AndonM.Coleman达成共识。这实际上不是sprintf的替代品。这样会更像这样,但这是Qt。
lpapp 2014年

就像@vinkris在回答中所说的那样,iomanip实现了格式化。而不是打印到stdoit,我会说“结果= out.str()”。
2014年

sprintf / snprintf允许格式化和打印到用户分配的字符数组,可能在堆栈上。如果使用snprintf(),则可以确保没有溢出。在这里,我们多次分配内存,而调用者没有直接访问它的权限。必须转换为字符串以获取输出。具有自定义std :: streambuf的std :: ostream需要用户缓冲区,这将是更好的匹配-当然,ostream / streambuf的构造/破坏会增加效率。
MGH

34

2019年8月更新:

看起来C ++ 20将会有std::format。参考实现是{fmt}。如果您现在正在寻找printf()替代方法,那么它将成为新的“标准”方法,值得考虑。

原版的:

使用Boost.Format。它具有printf类似语法,类型安全性,std::string结果以及许多其他漂亮的东西。你不会回去的。


14
...,除非您担心可执行文件的大小。:P
pradyunsg 2014年

这将产生多少影响?Boost依赖项将仅是标头,没有链接,对吗?
肯·威廉姆斯

1
@KenWilliams是的,Boost.Format仅是标头。我的Mac上的一个简单的“ hello,world”测试从10kB增加到78kB。在实际的项目中,多余的大小将在编译单元之间进行摊销(提供正确的链接器选项),而类型安全性还带来其他好处。
janm


7

您可以使用iomanip头文件来格式化输出流。检查一下


为什么有人对此表示反对?iomanip是不是在流中实现格式化的纯C ++方法吗?我认为这里的目标是避免将数据存储在C样式的字符串中,这是通过iomanip实现的。
2014年

7

这是C ++ sprintf的一个不错的功能。如果使用过多,流可能会变得很丑陋。

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',因此将其强制转换为char *using是合法的&str[0]

已经指出,可变参数不应该遵循按引用传递,并且c ++很好地在不需要时不复制字符串。在这种情况下,可以解决此问题。

std::string string_format(std::string fmt, ...) {

非常好的解决方案!我在这里对其进行了调整:stackoverflow.com/a/3742999/15161以更紧密地配合sprintf-usage。
slashmais 2012年

10
不过是非法的:(char*) str.c_str()抛弃const
MSalters

还存在潜伏的缓冲区溢出问题
Barney Szabolcs

@MSalters正确。在C ++ 11中有一种合法的方法。
whitequark

@whitequark:随意添加它作为答案。在“堆栈溢出”中,好的问题仍然存在,可以提出新的答案。
MSalters

0

使用stringstream可以达到相同的效果。此外,您可以包括<cstdio>并且仍然使用snprintf。


0

与其他选择相比sprintf(),这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()方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.