我应该在c++代码中使用printf吗?

时间:2023-01-14 16:19:03

I generally use cout and cerr to write text to the console. However sometimes I find it easier to use the good old printf statement. I use it when I need to format the output.

我通常使用cout和cerr向控制台写入文本。然而,有时我发现使用良好的旧printf语句更容易。我在需要格式化输出时使用它。

One example of where I would use this is:

我要用这个例子的一个例子是:

// Lets assume that I'm printing coordinates... 
printf("(%d,%d)\n", x, y);

// To do the same thing as above using cout....
cout << "(" << x << "," << y << ")" << endl;

I know I can format output using cout but I already know how to use the printf. Is there any reason I shouldn't use the printf statement?

我知道我可以用cout格式化输出,但我已经知道如何使用printf。有什么理由不使用printf语句吗?

19 个解决方案

#1


67  

My students, who learn cin and cout first, then learn printf later, overwhelmingly prefer printf (or more usually fprintf). I myself have found the printf model sufficiently readable that I have ported it to other programming languages. So has Olivier Danvy, who has even made it type-safe.

我的学生先学习cin和cout,然后再学习printf,他们非常喜欢printf(通常是fprintf)。我自己已经发现printf模型具有足够的可读性,我已经将它移植到其他编程语言中。奥利维尔·丹维(Olivier Danvy)也是如此,他甚至把它做成了类型安全的。

Provided you have a compiler that is capable of type-checking calls to printf, I see no reason not to use fprintf and friends in C++.

如果您有一个能够对printf进行类型检查的编译器,我认为没有理由不使用fprintf和c++中的朋友。

Disclaimer: I am a terrible C++ programmer.

免责声明:我是一个糟糕的c++程序员。

#2


48  

If you ever hope to i18n your program, stay away from iostreams. The problem is that it can be impossible to properly localize your strings if the sentence is composed of multiple fragments as is done with iostream.

如果你希望你的程序i18n,远离iostreams。问题是,如果句子是由多个片段组成的,那么就不可能像使用iostream那样正确地本地化字符串。

Besides the issue of message fragments, you also have an issue of ordering. Consider a report that prints a student's name and their grade point average:

除了消息片段的问题之外,还有排序的问题。考虑一份打印学生姓名和平均成绩的报告:

std::cout << name << " has a GPA of " << gpa << std::endl;

When you translate that to another language, the other language's grammar may need you to show the GPA before the name. AFAIK, iostreams has not way to reorder the interpolated values.

当你把它翻译成另一种语言时,另一种语言的语法可能需要你在名字前显示GPA。在AFAIK中,iostreams没有办法重新排列插值的值。

If you want the best of both worlds (type safety and being able to i18n), use Boost.Format.

如果您想要两者的优点(类型安全和能够i18n),使用boot . format。

#3


21  

Adaptability

Any attempt to printf a non-POD results in undefined behaviour:

任何试图打印非pod的尝试都会导致未定义的行为:

struct Foo { 
    virtual ~Foo() {}
    operator float() const { return 0.f; }
};

printf ("%f", Foo());

std::string foo;
printf ("%s", foo);

The above printf-calls yield undefined behaviour. Your compiler may warn you indeed, but those warnings are not required by the standards and not possible for format strings only known at runtime.

上面的printf调用产生了未定义的行为。您的编译器可能会警告您,但是这些警告不是标准所要求的,也不可能是只在运行时才知道的格式字符串。

IO-Streams:

i / o流:

std::cout << Foo();
std::string foo;
std::cout << foo;

Judge yourself.

判断自己。

Extensibility

struct Person {
    string first_name;
    string second_name;
};
std::ostream& operator<< (std::ostream &os, Person const& p) {
    return os << p.first_name << ", " << p.second_name;
}

cout << p;
cout << p;
some_file << p;

C:

C:

// inline everywhere
printf ("%s, %s", p.first_name, p.second_name);
printf ("%s, %s", p.first_name, p.second_name);
fprintf (some_file, "%s, %s", p.first_name, p.second_name);

or:

或者:

// re-usable (not common in my experience)
int person_fprint(FILE *f, const Person *p) {
    return fprintf(f, "%s, %s", p->first_name, p->second_name);
}
int person_print(const Person *p) {
    return person_fprint(stdout, p);
}

Person p;
....
person_print(&p);

Note how you have to take care of using the proper call arguments/signatures in C (e.g. person_fprint(stderr, ..., person_fprint(myfile, ...), where in C++, the "FILE-argument" is automatically "derived" from the expression. A more exact equivalent of this derivation is actually more like this:

注意如何在C中使用适当的调用参数/签名(例如person_fprint(stderr,……),person_fprint(myfile,…),在c++中,“文件参数”自动从表达式“派生”。这个推导的一个更确切的等价形式实际上更像这样:

FILE *fout = stdout;
...
fprintf(fout, "Hello World!\n");
person_fprint(fout, ...);
fprintf(fout, "\n");

I18N

We reuse our Person definition:

我们重用我们的Person定义:

cout << boost::format("Hello %1%") % p;
cout << boost::format("Na %1%, sei gegrüßt!") % p;

printf ("Hello %1$s, %2$s", p.first_name.c_str(), p.second_name.c_str()); 
printf ("Na %1$s, %2$s, sei gegrüßt!", 
        p.first_name.c_str(), p.second_name.c_str()); 

Judge yourself.

判断自己。

I find this less relevant as of today (2017). Maybe just a gut feeling, but I18N is not something that is done on a daily basis by your average C or C++ programmer. Plus, it's a pain in the a...natomy anyways.

我发现从今天(2017年)开始,这一点就不那么重要了。也许只是一种直觉,但I18N并不是普通的C或c++程序员每天都做的事情。另外,这是一种痛苦。natomy。

Performance

  1. Have you measured the actual significance of printf performance? Are your bottleneck applications seriously so lazy that the output of computation results is a bottleneck? Are you sure you need C++ at all?
  2. 你测量过printf性能的实际意义吗?您的瓶颈应用程序是否非常懒惰,以至于计算结果的输出成为瓶颈?你确定你需要c++吗?
  3. The dreaded performance penalty is to satisfy those of you who want to use a mix of printf and cout. It is a feature, not a bug!
  4. 令人恐惧的性能损失是为了满足那些希望使用printf和cout混合的人。它是一个特性,而不是bug!

If you use iostreams consistently, you can

如果你一直使用iostreams,你可以。

std::ios::sync_with_stdio(false);

and reap equal runtime with a good compiler:

用一个好的编译器获得相同的运行时:

#include <cstdio>
#include <iostream>
#include <ctime>
#include <fstream>

void ios_test (int n) {
    for (int i=0; i<n; ++i) {
        std::cout << "foobarfrob" << i;
    }
}

void c_test (int n) {
    for (int i=0; i<n; ++i) {
        printf ("foobarfrob%d", i);
    }
}


int main () {
    const clock_t a_start = clock();
    ios_test (10024*1024);
    const double a = (clock() - a_start) / double(CLOCKS_PER_SEC);

    const clock_t p_start = clock();
    c_test (10024*1024);
    const double p = (clock() - p_start) / double(CLOCKS_PER_SEC);

    std::ios::sync_with_stdio(false);
    const clock_t b_start = clock();
    ios_test (10024*1024);
    const double b = (clock() - b_start) / double(CLOCKS_PER_SEC);


    std::ofstream res ("RESULTS");
    res << "C ..............: " << p << " sec\n"
        << "C++, sync with C: " << a << " sec\n"
        << "C++, non-sync ..: " << b << " sec\n";
}

Results (g++ -O3 synced-unsynced-printf.cc, ./a.out > /dev/null, cat RESULTS):

结果(g + + o3 synced-unsynced-printf。cc,。/。输出> /dev/null, cat结果):

C ..............: 1.1 sec
C++, sync with C: 1.76 sec
C++, non-sync ..: 1.01 sec

Judge ... yourself.

法官……你自己。

No. You won't forbid me my printf.

You can haz a typesafe, I18N friendly printf in C++11, thanks to variadic templates. And you will be able to have them very, very performant using user-defined literals, i.e. it will be possible to write a fully static incarnation.

您可以在c++ 11中使用一个typesafe, I18N友好的printf,多亏了可变模板。你可以用用户定义的文字来表现它们,也就是说,你可以写一个完全静态的版本。

I have a proof of concept. Back then, support for C++11 was not as mature as it is now, but you get an idea.

我有一个概念证明。那时,对c++ 11的支持并不像现在这样成熟,但是你会有一个想法。

Temporal Adaptability

// foo.h
...
struct Frob {
    unsigned int x;
};
...

// alpha.cpp
... printf ("%u", frob.x); ...

// bravo.cpp
... printf ("%u", frob.x); ...

// charlie.cpp
... printf ("%u", frob.x); ...

// delta.cpp
... printf ("%u", frob.x); ...

Later, your data grows so big you must do

稍后,您的数据变得非常大,您必须这么做

// foo.h
...
    unsigned long long x;
...

It is an interesting exercise maintaining that and doing it bug-free. Especially when other, non-coupled projects use foo.h.

这是一个有趣的练习,保持它并且做它没有bug。特别是当其他非耦合项目使用foo.h时。

Other.

  • Bug Potential: There's a lot of space to commit mistakes with printf, especially when you throw user input bases strings in the mix (think of your I18N team). You must take care to properly escape every such format string, you must be sure to pass the right arguments, etc. etc..

    Bug潜力:在printf中存在大量的错误,特别是当您在混合中抛出用户输入基础字符串时(想想您的I18N团队)。您必须注意正确地转义每个这样的格式字符串,您必须确保传递正确的参数等等。

  • IO-Streams make my binary bigger: If this is a more important issue than maintainability, code-quality, reuseability, then (after verifying the issue!) use printf.

    IO-Streams使我的二进制更大:如果这是一个比可维护性、代码质量、可重用性更重要的问题,那么(在验证这个问题之后!)使用printf。

#4


19  

Use boost::format. You get type safety, std::string support, printf like interface, ability to use cout, and lots of other good stuff. You won't go back.

使用boost::格式。您可以获得类型安全,std::string support, printf like interface,使用cout的能力,以及许多其他的好东西。你不会回去。

#5


17  

I use printf because I hate the ugly <<cout<< syntax.

我使用printf是因为我讨厌难看的<

#6


7  

No reason at all. I think it's just some strange ideology that drives people towards using only C++ libraries even though good old C libs are still valid. I'm a C++ guy and I use C functions a lot too. Never had any problems with them.

没有理由。我认为这只是一些奇怪的意识形态,驱使人们只使用c++库,尽管好的旧C语言仍然有效。我是一个c++的人,我也经常使用C函数。他们从来没有任何问题。

#7


6  

Streams are the canonical way. Try making this code work with printf:

流是规范的方式。尝试使用printf使此代码工作:

template <typename T>
void output(const T& pX)
{
    std::cout << pX << std::endl;
}

Good luck.

祝你好运。

What I mean is, you can make operators to allow your types to be outputted to ostream's, and without hassle use it just like any other type. printf doesn't fit the the generality of C++, or more specifically templates.

我的意思是,您可以使操作符允许您的类型输出到ostream's,并且不像其他类型那样麻烦地使用它。printf不适合c++的通用性,或者更具体的模板。

There's more than usability. There's also consistency. In all my projects, I have cout (and cerr and clog) tee'd to also output to a file. If you use printf, you skip all of that. Additionally, consistency itself is a good thing; mixing cout and printf, while perfectly valid, is ugly.

有更多的可用性。也有一致性。在我的所有项目中,cout(以及cerr和clog) tee也会输出到一个文件。如果您使用printf,您将跳过所有这些。此外,一致性本身也是一件好事;混合cout和printf,虽然完全有效,但是很难看。

If you have an object, and you want to make it output-able, the cleanest way to do this is overload operator<< for that class. How are you going to use printf then? You're going to end up with code jumbled with cout's and printf's.

如果你有一个对象,并且你想让它输出,最干净的方法就是重载操作符< <在那个类中。那你怎么用printf呢?最后你会发现代码混杂了cout和printf。< p>

If you really want formatting, use Boost.Format while maintaining the stream interface. Consistency and formatting.

如果您确实需要格式化,请使用Boost。在维护流接口时格式化。一致性和格式化。

#8


5  

Use printf. Do not use C++ streams. printf gives you much better control (such as float precision etc.). The code is also usually shorter and more readable.

使用printf。不要使用c++流。printf提供了更好的控制(例如浮点精度等)。代码通常也更短,可读性更好。

Google C++ style guide agrees.

谷歌c++风格指南同意。

Do not use streams, except where required by a logging interface. Use printf-like routines instead.

不要使用流,除非日志接口需要。使用类似printf的例程。

There are various pros and cons to using streams, but in this case, as in many other cases, consistency trumps the debate. Do not use streams in your code.

使用流有不同的利弊,但是在这种情况下,和许多其他情况一样,一致性胜过争论。不要在代码中使用流。

#9


5  

On the whole I agree (hate the << syntax especially if you need complex formatting)

总的来说,我同意(讨厌 <语法,尤其是需要复杂格式的时候)< p>

But I should point out the safety aspects.

但我应该指出安全方面的问题。

printf("%x",2.0f)
printf("%x %x",2)
printf("%x",2,2)

Probably won't be noticed by the compiler but could crash your app.

编译器可能不会注意到你,但是你的应用可能会崩溃。

#10


4  

Use whatever fits your needs and preferences. If you're comfortable with printf then by all means use it. If you're happier with iostreams stick to 'em. Mix and match as best fits your requirements. This is software, after all - there's better ways and worse ways, but seldom is there only ONE way.

使用适合你的需求和偏好的东西。如果你喜欢printf,那么一定要使用它。如果你对iostreams更满意,那么就把它和你的要求结合起来。这毕竟是软件——有更好的方法和更坏的方法,但很少只有一种方法。

Share and enjoy.

分享和享受。

#11


3  

I do not like printf. Its lack of type-safety makes it dangerous to use, plus the need to remember format specifiers is a pain. The templated operators that smartly do the right thing are much better. So I always use the C++ streams in C++.

我不喜欢printf。它缺乏类型安全,因此使用它是危险的,再加上需要记住格式说明符是痛苦的。做正确事情的模板操作符要好得多。所以我总是在c++中使用c++流。

Granted, many people prefer printf, for other reasons, enumerated elsewhere.

诚然,出于其他原因,许多人更喜欢在其他地方列举的printf。

#12


3  

I often "drop back" to using printf(), but more often snprintf() for easier formatted output. When programming in C++ I use this wrapper I wrote a while back, called like this (to use your example as above): cout << format("(%d,%d)\n", x, y);

我经常“退回”使用printf(),但更经常的是snprintf(),以便更容易地格式化输出。在c++编程时,我使用了我以前写过的这个包装器,调用方式如下(使用上面的示例):cout < format(“(%d,%d)\n”,x, y);

Here's the header (stdiomm.h):

这是头(stdiomm.h):

#pragma once

#include <cstdarg>
#include <string>

template <typename T>
std::basic_string<T> format(T const *format, ...);

template <typename T>
std::basic_string<T> vformat(T const *format, va_list args);

And the source (stdiomm.cpp):

和源(stdiomm.cpp):

#include "stdiomm.h"
#include <boost/scoped_array.hpp>
#include <cstdio>

template <>
std::wstring vformat(wchar_t const *format, va_list arguments)
{
#if defined(_WIN32)
    int required(_vscwprintf(format, arguments));
    assert(required >= 0);
    boost::scoped_array<wchar_t> buffer(new wchar_t[required + 1]);
    int written(vswprintf(buffer.get(), required + 1, format, arguments));
    assert(written == required);
    return std::wstring(buffer.get(), written);
#else
#   error "No implementation yet"
#endif
}

template <>
std::string vformat(char const *format, va_list arguments)
{
#if defined(_WIN32)
    int required(_vscprintf(format, arguments));
    assert(required >= 0);
    boost::scoped_array<char> buffer(new char[required + 1]);
    int written(vsnprintf(buffer.get(), required + 1, format, arguments));
    assert(written == required);
    return std::string(buffer.get(), written);
#else
    char *buffer;
    int printed = vasprintf(&buffer, format, arguments);
    assert(printed != -1);
    std::string retval(buffer, printed);
    free(buffer);
    return retval;      
#endif
}

template <typename T>
std::basic_string<T> format(T const *format, ...)
{
    va_list ap;
    va_start(ap, format);
    std::basic_string<T> retval(vformat(format, ap));
    va_end(ap);
    return retval;
}

template std::wstring format(wchar_t const *format, ...);
template std::string format(char const *format, ...);

Update

After reading some of the other answers, I might have to make a switch to boost::format() myself!

在阅读了其他一些答案之后,我可能需要切换到boost::format()我自己!

#13


1  

Even though the question is rather old, I want to add my two cents.

尽管这个问题很老了,我还是想补充一点。

Printing user-created objects with printf()

使用printf()打印用户创建的对象

This is rather simple if you think about it - you can stringify your type and sent the string to printf:

这是相当简单的,如果您考虑一下——您可以将您的类型stringify,并将字符串发送到printf:

std::string to_string(const MyClass &x)
{
     return to_string(x.first)+" "+to_string(x.second);
}

//...

printf("%s is awesome", to_string(my_object).c_str()); //more or less

A shame there wasn't (there is C++11 to_string()) standarized C++ interface to stringify objects...

遗憾的是,没有(c++ 11 to_string()标准化的c++接口来stringify对象……

printf() pitfall

printf()的陷阱

A single flag - %n

一个标记- %n

The only one that is an output parameter - it expects pointer to int. It writes number of succesfully written characters to location pointed by this pointer. Skillful use of it can trigger overrun, which is security vulnerability (see printf() format string attack).

唯一一个是输出参数——它期望指针指向int。它将成功写入的字符数写入指针指向的位置。熟练地使用它可以触发溢出,这是安全漏洞(参见printf()格式字符串攻击)。

#14


1  

You can get the best of both worlds with the fmt library which combines safety and extensibility of iostreams with usability and performance of (s)printf. Example:

fmt库将iostreams的安全性和可扩展性与printf的可用性和性能结合在一起,您可以充分利用这两个方面。例子:

std::string = fmt::format("The answer is {}", 42);

The library supports Python-like and printf format string syntax.

库支持类似python的和printf格式的字符串语法。

Disclaimer: I'm the author of the fmt library.

免责声明:我是fmt图书馆的作者。

#15


0  

I almost always use printf for temporary debugging statements. For more permanent code, I prefer the 'c' streams as they are The C++ Way. Although boost::format looks promising and might replace my stream usage (especially for complexly formatted output), probably nothing will replace printf for me for a long time.

我几乎总是将printf用于临时调试语句。对于更持久的代码,我更喜欢“c”流,因为它们是c++的方式。虽然boost:::format看起来很有前途,并且可能会取代我的流使用(特别是对于复杂格式的输出),但是在很长一段时间内,可能没有任何东西会取代printf。

#16


0  

C++ streams are overrated, after all they're in fact just classes with an overloaded operator <<.
I've read many times that streams are the C++ way as printf is the C way, but they are both library features available in C++, so you should use what suits best.
I mostly prefer printf, but I've also used streams, which provide cleaner code and prevent you from having to match % placeholders to arguments.

c++流被高估了,毕竟它们实际上只是带有重载操作符的类。我读过很多次流是c++的方式,因为printf是C的方式,但是它们都是c++中可用的库特性,所以您应该使用最适合的方法。我更喜欢printf,但我也使用了streams,它提供了更清晰的代码,并防止您不得不将%占位符与参数匹配。

#17


0  

It depends on the situation. Nothing is perfect. I use both. Streams are good for custom types as you can overload the >> operator in ostream. But when it comes to spacing and etc it's better to use printf(). stringstream and like are better than the C style strcat(). So use one that's appropriate for the situation.

这要视情况而定。没有什么是完美的。我同时使用。流对于自定义类型很有用,因为您可以在ostream中重载>>操作符。但是当涉及到间距等时,最好使用printf()。stringstream和like比C风格的strcat()要好。所以用一个适合这种情况的。

#18


0  

I have read warnings saying that cout and cerr are unsafe for multithreading. If true, this is a good reason to avoid using them. Note: I use GNU g++ with openMP.

我读过警告说cout和cerr对于多线程不安全。如果是真的,这是一个避免使用它们的好理由。注意:我在openMP中使用GNU g++。

#19


-1  

streams are preferred in cpp as they adhere to the object oriented paradigm of cpp, beside being type safe.

流在cpp中是首选的,因为它们遵循cpp的面向对象范式,除了类型安全之外。

printf , on the other hand is more of a functional approach.

另一方面,printf则是函数式的方法。

only reason for not using printf in cpp code that i can think of is not being object oriented.

我认为在cpp代码中不使用printf的唯一原因是它不是面向对象的。

its more of a personal choice.

这更多的是一个人的选择。

#1


67  

My students, who learn cin and cout first, then learn printf later, overwhelmingly prefer printf (or more usually fprintf). I myself have found the printf model sufficiently readable that I have ported it to other programming languages. So has Olivier Danvy, who has even made it type-safe.

我的学生先学习cin和cout,然后再学习printf,他们非常喜欢printf(通常是fprintf)。我自己已经发现printf模型具有足够的可读性,我已经将它移植到其他编程语言中。奥利维尔·丹维(Olivier Danvy)也是如此,他甚至把它做成了类型安全的。

Provided you have a compiler that is capable of type-checking calls to printf, I see no reason not to use fprintf and friends in C++.

如果您有一个能够对printf进行类型检查的编译器,我认为没有理由不使用fprintf和c++中的朋友。

Disclaimer: I am a terrible C++ programmer.

免责声明:我是一个糟糕的c++程序员。

#2


48  

If you ever hope to i18n your program, stay away from iostreams. The problem is that it can be impossible to properly localize your strings if the sentence is composed of multiple fragments as is done with iostream.

如果你希望你的程序i18n,远离iostreams。问题是,如果句子是由多个片段组成的,那么就不可能像使用iostream那样正确地本地化字符串。

Besides the issue of message fragments, you also have an issue of ordering. Consider a report that prints a student's name and their grade point average:

除了消息片段的问题之外,还有排序的问题。考虑一份打印学生姓名和平均成绩的报告:

std::cout << name << " has a GPA of " << gpa << std::endl;

When you translate that to another language, the other language's grammar may need you to show the GPA before the name. AFAIK, iostreams has not way to reorder the interpolated values.

当你把它翻译成另一种语言时,另一种语言的语法可能需要你在名字前显示GPA。在AFAIK中,iostreams没有办法重新排列插值的值。

If you want the best of both worlds (type safety and being able to i18n), use Boost.Format.

如果您想要两者的优点(类型安全和能够i18n),使用boot . format。

#3


21  

Adaptability

Any attempt to printf a non-POD results in undefined behaviour:

任何试图打印非pod的尝试都会导致未定义的行为:

struct Foo { 
    virtual ~Foo() {}
    operator float() const { return 0.f; }
};

printf ("%f", Foo());

std::string foo;
printf ("%s", foo);

The above printf-calls yield undefined behaviour. Your compiler may warn you indeed, but those warnings are not required by the standards and not possible for format strings only known at runtime.

上面的printf调用产生了未定义的行为。您的编译器可能会警告您,但是这些警告不是标准所要求的,也不可能是只在运行时才知道的格式字符串。

IO-Streams:

i / o流:

std::cout << Foo();
std::string foo;
std::cout << foo;

Judge yourself.

判断自己。

Extensibility

struct Person {
    string first_name;
    string second_name;
};
std::ostream& operator<< (std::ostream &os, Person const& p) {
    return os << p.first_name << ", " << p.second_name;
}

cout << p;
cout << p;
some_file << p;

C:

C:

// inline everywhere
printf ("%s, %s", p.first_name, p.second_name);
printf ("%s, %s", p.first_name, p.second_name);
fprintf (some_file, "%s, %s", p.first_name, p.second_name);

or:

或者:

// re-usable (not common in my experience)
int person_fprint(FILE *f, const Person *p) {
    return fprintf(f, "%s, %s", p->first_name, p->second_name);
}
int person_print(const Person *p) {
    return person_fprint(stdout, p);
}

Person p;
....
person_print(&p);

Note how you have to take care of using the proper call arguments/signatures in C (e.g. person_fprint(stderr, ..., person_fprint(myfile, ...), where in C++, the "FILE-argument" is automatically "derived" from the expression. A more exact equivalent of this derivation is actually more like this:

注意如何在C中使用适当的调用参数/签名(例如person_fprint(stderr,……),person_fprint(myfile,…),在c++中,“文件参数”自动从表达式“派生”。这个推导的一个更确切的等价形式实际上更像这样:

FILE *fout = stdout;
...
fprintf(fout, "Hello World!\n");
person_fprint(fout, ...);
fprintf(fout, "\n");

I18N

We reuse our Person definition:

我们重用我们的Person定义:

cout << boost::format("Hello %1%") % p;
cout << boost::format("Na %1%, sei gegrüßt!") % p;

printf ("Hello %1$s, %2$s", p.first_name.c_str(), p.second_name.c_str()); 
printf ("Na %1$s, %2$s, sei gegrüßt!", 
        p.first_name.c_str(), p.second_name.c_str()); 

Judge yourself.

判断自己。

I find this less relevant as of today (2017). Maybe just a gut feeling, but I18N is not something that is done on a daily basis by your average C or C++ programmer. Plus, it's a pain in the a...natomy anyways.

我发现从今天(2017年)开始,这一点就不那么重要了。也许只是一种直觉,但I18N并不是普通的C或c++程序员每天都做的事情。另外,这是一种痛苦。natomy。

Performance

  1. Have you measured the actual significance of printf performance? Are your bottleneck applications seriously so lazy that the output of computation results is a bottleneck? Are you sure you need C++ at all?
  2. 你测量过printf性能的实际意义吗?您的瓶颈应用程序是否非常懒惰,以至于计算结果的输出成为瓶颈?你确定你需要c++吗?
  3. The dreaded performance penalty is to satisfy those of you who want to use a mix of printf and cout. It is a feature, not a bug!
  4. 令人恐惧的性能损失是为了满足那些希望使用printf和cout混合的人。它是一个特性,而不是bug!

If you use iostreams consistently, you can

如果你一直使用iostreams,你可以。

std::ios::sync_with_stdio(false);

and reap equal runtime with a good compiler:

用一个好的编译器获得相同的运行时:

#include <cstdio>
#include <iostream>
#include <ctime>
#include <fstream>

void ios_test (int n) {
    for (int i=0; i<n; ++i) {
        std::cout << "foobarfrob" << i;
    }
}

void c_test (int n) {
    for (int i=0; i<n; ++i) {
        printf ("foobarfrob%d", i);
    }
}


int main () {
    const clock_t a_start = clock();
    ios_test (10024*1024);
    const double a = (clock() - a_start) / double(CLOCKS_PER_SEC);

    const clock_t p_start = clock();
    c_test (10024*1024);
    const double p = (clock() - p_start) / double(CLOCKS_PER_SEC);

    std::ios::sync_with_stdio(false);
    const clock_t b_start = clock();
    ios_test (10024*1024);
    const double b = (clock() - b_start) / double(CLOCKS_PER_SEC);


    std::ofstream res ("RESULTS");
    res << "C ..............: " << p << " sec\n"
        << "C++, sync with C: " << a << " sec\n"
        << "C++, non-sync ..: " << b << " sec\n";
}

Results (g++ -O3 synced-unsynced-printf.cc, ./a.out > /dev/null, cat RESULTS):

结果(g + + o3 synced-unsynced-printf。cc,。/。输出> /dev/null, cat结果):

C ..............: 1.1 sec
C++, sync with C: 1.76 sec
C++, non-sync ..: 1.01 sec

Judge ... yourself.

法官……你自己。

No. You won't forbid me my printf.

You can haz a typesafe, I18N friendly printf in C++11, thanks to variadic templates. And you will be able to have them very, very performant using user-defined literals, i.e. it will be possible to write a fully static incarnation.

您可以在c++ 11中使用一个typesafe, I18N友好的printf,多亏了可变模板。你可以用用户定义的文字来表现它们,也就是说,你可以写一个完全静态的版本。

I have a proof of concept. Back then, support for C++11 was not as mature as it is now, but you get an idea.

我有一个概念证明。那时,对c++ 11的支持并不像现在这样成熟,但是你会有一个想法。

Temporal Adaptability

// foo.h
...
struct Frob {
    unsigned int x;
};
...

// alpha.cpp
... printf ("%u", frob.x); ...

// bravo.cpp
... printf ("%u", frob.x); ...

// charlie.cpp
... printf ("%u", frob.x); ...

// delta.cpp
... printf ("%u", frob.x); ...

Later, your data grows so big you must do

稍后,您的数据变得非常大,您必须这么做

// foo.h
...
    unsigned long long x;
...

It is an interesting exercise maintaining that and doing it bug-free. Especially when other, non-coupled projects use foo.h.

这是一个有趣的练习,保持它并且做它没有bug。特别是当其他非耦合项目使用foo.h时。

Other.

  • Bug Potential: There's a lot of space to commit mistakes with printf, especially when you throw user input bases strings in the mix (think of your I18N team). You must take care to properly escape every such format string, you must be sure to pass the right arguments, etc. etc..

    Bug潜力:在printf中存在大量的错误,特别是当您在混合中抛出用户输入基础字符串时(想想您的I18N团队)。您必须注意正确地转义每个这样的格式字符串,您必须确保传递正确的参数等等。

  • IO-Streams make my binary bigger: If this is a more important issue than maintainability, code-quality, reuseability, then (after verifying the issue!) use printf.

    IO-Streams使我的二进制更大:如果这是一个比可维护性、代码质量、可重用性更重要的问题,那么(在验证这个问题之后!)使用printf。

#4


19  

Use boost::format. You get type safety, std::string support, printf like interface, ability to use cout, and lots of other good stuff. You won't go back.

使用boost::格式。您可以获得类型安全,std::string support, printf like interface,使用cout的能力,以及许多其他的好东西。你不会回去。

#5


17  

I use printf because I hate the ugly <<cout<< syntax.

我使用printf是因为我讨厌难看的<

#6


7  

No reason at all. I think it's just some strange ideology that drives people towards using only C++ libraries even though good old C libs are still valid. I'm a C++ guy and I use C functions a lot too. Never had any problems with them.

没有理由。我认为这只是一些奇怪的意识形态,驱使人们只使用c++库,尽管好的旧C语言仍然有效。我是一个c++的人,我也经常使用C函数。他们从来没有任何问题。

#7


6  

Streams are the canonical way. Try making this code work with printf:

流是规范的方式。尝试使用printf使此代码工作:

template <typename T>
void output(const T& pX)
{
    std::cout << pX << std::endl;
}

Good luck.

祝你好运。

What I mean is, you can make operators to allow your types to be outputted to ostream's, and without hassle use it just like any other type. printf doesn't fit the the generality of C++, or more specifically templates.

我的意思是,您可以使操作符允许您的类型输出到ostream's,并且不像其他类型那样麻烦地使用它。printf不适合c++的通用性,或者更具体的模板。

There's more than usability. There's also consistency. In all my projects, I have cout (and cerr and clog) tee'd to also output to a file. If you use printf, you skip all of that. Additionally, consistency itself is a good thing; mixing cout and printf, while perfectly valid, is ugly.

有更多的可用性。也有一致性。在我的所有项目中,cout(以及cerr和clog) tee也会输出到一个文件。如果您使用printf,您将跳过所有这些。此外,一致性本身也是一件好事;混合cout和printf,虽然完全有效,但是很难看。

If you have an object, and you want to make it output-able, the cleanest way to do this is overload operator<< for that class. How are you going to use printf then? You're going to end up with code jumbled with cout's and printf's.

如果你有一个对象,并且你想让它输出,最干净的方法就是重载操作符< <在那个类中。那你怎么用printf呢?最后你会发现代码混杂了cout和printf。< p>

If you really want formatting, use Boost.Format while maintaining the stream interface. Consistency and formatting.

如果您确实需要格式化,请使用Boost。在维护流接口时格式化。一致性和格式化。

#8


5  

Use printf. Do not use C++ streams. printf gives you much better control (such as float precision etc.). The code is also usually shorter and more readable.

使用printf。不要使用c++流。printf提供了更好的控制(例如浮点精度等)。代码通常也更短,可读性更好。

Google C++ style guide agrees.

谷歌c++风格指南同意。

Do not use streams, except where required by a logging interface. Use printf-like routines instead.

不要使用流,除非日志接口需要。使用类似printf的例程。

There are various pros and cons to using streams, but in this case, as in many other cases, consistency trumps the debate. Do not use streams in your code.

使用流有不同的利弊,但是在这种情况下,和许多其他情况一样,一致性胜过争论。不要在代码中使用流。

#9


5  

On the whole I agree (hate the << syntax especially if you need complex formatting)

总的来说,我同意(讨厌 <语法,尤其是需要复杂格式的时候)< p>

But I should point out the safety aspects.

但我应该指出安全方面的问题。

printf("%x",2.0f)
printf("%x %x",2)
printf("%x",2,2)

Probably won't be noticed by the compiler but could crash your app.

编译器可能不会注意到你,但是你的应用可能会崩溃。

#10


4  

Use whatever fits your needs and preferences. If you're comfortable with printf then by all means use it. If you're happier with iostreams stick to 'em. Mix and match as best fits your requirements. This is software, after all - there's better ways and worse ways, but seldom is there only ONE way.

使用适合你的需求和偏好的东西。如果你喜欢printf,那么一定要使用它。如果你对iostreams更满意,那么就把它和你的要求结合起来。这毕竟是软件——有更好的方法和更坏的方法,但很少只有一种方法。

Share and enjoy.

分享和享受。

#11


3  

I do not like printf. Its lack of type-safety makes it dangerous to use, plus the need to remember format specifiers is a pain. The templated operators that smartly do the right thing are much better. So I always use the C++ streams in C++.

我不喜欢printf。它缺乏类型安全,因此使用它是危险的,再加上需要记住格式说明符是痛苦的。做正确事情的模板操作符要好得多。所以我总是在c++中使用c++流。

Granted, many people prefer printf, for other reasons, enumerated elsewhere.

诚然,出于其他原因,许多人更喜欢在其他地方列举的printf。

#12


3  

I often "drop back" to using printf(), but more often snprintf() for easier formatted output. When programming in C++ I use this wrapper I wrote a while back, called like this (to use your example as above): cout << format("(%d,%d)\n", x, y);

我经常“退回”使用printf(),但更经常的是snprintf(),以便更容易地格式化输出。在c++编程时,我使用了我以前写过的这个包装器,调用方式如下(使用上面的示例):cout < format(“(%d,%d)\n”,x, y);

Here's the header (stdiomm.h):

这是头(stdiomm.h):

#pragma once

#include <cstdarg>
#include <string>

template <typename T>
std::basic_string<T> format(T const *format, ...);

template <typename T>
std::basic_string<T> vformat(T const *format, va_list args);

And the source (stdiomm.cpp):

和源(stdiomm.cpp):

#include "stdiomm.h"
#include <boost/scoped_array.hpp>
#include <cstdio>

template <>
std::wstring vformat(wchar_t const *format, va_list arguments)
{
#if defined(_WIN32)
    int required(_vscwprintf(format, arguments));
    assert(required >= 0);
    boost::scoped_array<wchar_t> buffer(new wchar_t[required + 1]);
    int written(vswprintf(buffer.get(), required + 1, format, arguments));
    assert(written == required);
    return std::wstring(buffer.get(), written);
#else
#   error "No implementation yet"
#endif
}

template <>
std::string vformat(char const *format, va_list arguments)
{
#if defined(_WIN32)
    int required(_vscprintf(format, arguments));
    assert(required >= 0);
    boost::scoped_array<char> buffer(new char[required + 1]);
    int written(vsnprintf(buffer.get(), required + 1, format, arguments));
    assert(written == required);
    return std::string(buffer.get(), written);
#else
    char *buffer;
    int printed = vasprintf(&buffer, format, arguments);
    assert(printed != -1);
    std::string retval(buffer, printed);
    free(buffer);
    return retval;      
#endif
}

template <typename T>
std::basic_string<T> format(T const *format, ...)
{
    va_list ap;
    va_start(ap, format);
    std::basic_string<T> retval(vformat(format, ap));
    va_end(ap);
    return retval;
}

template std::wstring format(wchar_t const *format, ...);
template std::string format(char const *format, ...);

Update

After reading some of the other answers, I might have to make a switch to boost::format() myself!

在阅读了其他一些答案之后,我可能需要切换到boost::format()我自己!

#13


1  

Even though the question is rather old, I want to add my two cents.

尽管这个问题很老了,我还是想补充一点。

Printing user-created objects with printf()

使用printf()打印用户创建的对象

This is rather simple if you think about it - you can stringify your type and sent the string to printf:

这是相当简单的,如果您考虑一下——您可以将您的类型stringify,并将字符串发送到printf:

std::string to_string(const MyClass &x)
{
     return to_string(x.first)+" "+to_string(x.second);
}

//...

printf("%s is awesome", to_string(my_object).c_str()); //more or less

A shame there wasn't (there is C++11 to_string()) standarized C++ interface to stringify objects...

遗憾的是,没有(c++ 11 to_string()标准化的c++接口来stringify对象……

printf() pitfall

printf()的陷阱

A single flag - %n

一个标记- %n

The only one that is an output parameter - it expects pointer to int. It writes number of succesfully written characters to location pointed by this pointer. Skillful use of it can trigger overrun, which is security vulnerability (see printf() format string attack).

唯一一个是输出参数——它期望指针指向int。它将成功写入的字符数写入指针指向的位置。熟练地使用它可以触发溢出,这是安全漏洞(参见printf()格式字符串攻击)。

#14


1  

You can get the best of both worlds with the fmt library which combines safety and extensibility of iostreams with usability and performance of (s)printf. Example:

fmt库将iostreams的安全性和可扩展性与printf的可用性和性能结合在一起,您可以充分利用这两个方面。例子:

std::string = fmt::format("The answer is {}", 42);

The library supports Python-like and printf format string syntax.

库支持类似python的和printf格式的字符串语法。

Disclaimer: I'm the author of the fmt library.

免责声明:我是fmt图书馆的作者。

#15


0  

I almost always use printf for temporary debugging statements. For more permanent code, I prefer the 'c' streams as they are The C++ Way. Although boost::format looks promising and might replace my stream usage (especially for complexly formatted output), probably nothing will replace printf for me for a long time.

我几乎总是将printf用于临时调试语句。对于更持久的代码,我更喜欢“c”流,因为它们是c++的方式。虽然boost:::format看起来很有前途,并且可能会取代我的流使用(特别是对于复杂格式的输出),但是在很长一段时间内,可能没有任何东西会取代printf。

#16


0  

C++ streams are overrated, after all they're in fact just classes with an overloaded operator <<.
I've read many times that streams are the C++ way as printf is the C way, but they are both library features available in C++, so you should use what suits best.
I mostly prefer printf, but I've also used streams, which provide cleaner code and prevent you from having to match % placeholders to arguments.

c++流被高估了,毕竟它们实际上只是带有重载操作符的类。我读过很多次流是c++的方式,因为printf是C的方式,但是它们都是c++中可用的库特性,所以您应该使用最适合的方法。我更喜欢printf,但我也使用了streams,它提供了更清晰的代码,并防止您不得不将%占位符与参数匹配。

#17


0  

It depends on the situation. Nothing is perfect. I use both. Streams are good for custom types as you can overload the >> operator in ostream. But when it comes to spacing and etc it's better to use printf(). stringstream and like are better than the C style strcat(). So use one that's appropriate for the situation.

这要视情况而定。没有什么是完美的。我同时使用。流对于自定义类型很有用,因为您可以在ostream中重载>>操作符。但是当涉及到间距等时,最好使用printf()。stringstream和like比C风格的strcat()要好。所以用一个适合这种情况的。

#18


0  

I have read warnings saying that cout and cerr are unsafe for multithreading. If true, this is a good reason to avoid using them. Note: I use GNU g++ with openMP.

我读过警告说cout和cerr对于多线程不安全。如果是真的,这是一个避免使用它们的好理由。注意:我在openMP中使用GNU g++。

#19


-1  

streams are preferred in cpp as they adhere to the object oriented paradigm of cpp, beside being type safe.

流在cpp中是首选的,因为它们遵循cpp的面向对象范式,除了类型安全之外。

printf , on the other hand is more of a functional approach.

另一方面,printf则是函数式的方法。

only reason for not using printf in cpp code that i can think of is not being object oriented.

我认为在cpp代码中不使用printf的唯一原因是它不是面向对象的。

its more of a personal choice.

这更多的是一个人的选择。