77

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.

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?

MD XF
  • 7,860
  • 7
  • 40
  • 71
Bob Dylan
  • 4,393
  • 9
  • 40
  • 58
  • 3
    For console I/O *es macht nichts* (it doesn't matter). In the big picture, `printf` is not compatible with C++ streams. C++ streams allow you to easily convert your console output to a file. (Although you can do similar with `fprintf`). – Thomas Matthews Jan 07 '10 at 01:00
  • 1
    what about using sprintf + cout then? – Larry Watanabe Jan 07 '10 at 02:32
  • 14
    Mote that your two lines are not strictly equivalent. `endl` also flushes the stream, as if you had written `printf("(%d,%d)\n", x, y); fflush(stdout);` This can add a *big* performance hit if executed repeatedly in a loop. To get a real equivalent of your printf statement in C++ you should write `cout << "(" << x << "," << y << ")\n";` – Didier Trosset Jan 07 '10 at 08:49
  • 2
    @bobobobo, A typo for "Note". – strager Sep 12 '12 at 01:47
  • Possible duplicate of ['printf' vs. 'cout' in C++](https://stackoverflow.com/questions/2872543/printf-vs-cout-in-c) – Konrad Borowski Jun 07 '18 at 13:23

20 Answers20

77

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.

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++.

Disclaimer: I am a terrible C++ programmer.

Norman Ramsey
  • 198,648
  • 61
  • 360
  • 533
  • 17
    I use Java's `String.format` a lot. In C++, I use Boost.Format a lot, which is iostreams-friendly but also somewhat `printf`-compatible. – C. K. Young Jan 07 '10 at 01:08
  • 5
    *printf's lack of type safety is mitigated but not eliminated by compilers that check those calls, since using variables as format strings is a perfectly valid use case. e.g: i18n. This function can blow up in so many ways, it's not even funny. I just don't use it any more. We have access to perfectly good formatters such as boost::format or Qt::arg. – rpg Jan 07 '10 at 11:49
  • @rpg: I think the tradeoff is between readability and type safety. I think it's reasonable for different applications to make different tradeoffs. Once you're into i18n, readability is already halfway out the window anyway, and I agree type safety trumps printf in that situation. Interestingly, the way `boost::format` works is somewhat similar to the way Olivier Danvy's ML code works. – Norman Ramsey Jan 07 '10 at 16:01
  • 2
    @Norman Ramsey: I see the `type safety problem` with `printf()` mentioned several times. *What exactly is the type safety problem with printf()?* – Lazer Apr 25 '10 at 19:53
  • @Norman Ramsey: I am not sure what kind of problem can arise if the types are not checked. Can you please quote an example? I use `printf()` in C all the time. Never faced a problem. – Lazer Apr 25 '10 at 20:21
  • @eSKay: It's very rare to have an issue in practice. But try `char *fmt = "%s %s"; printf(fmt, "hello");` or `char *fmt = "%s"; printf(fmt, main);`. – Norman Ramsey Apr 25 '10 at 22:50
  • @Lazer: Buffer overruns, undefined behaviour, coredumps, off-by-one-errors, security-vulnerabilities. You may want to look up format string attack on wikipedia. – Sebastian Mach Jan 22 '13 at 11:06
49

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.

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.

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

R Samuel Klatchko
  • 74,869
  • 16
  • 134
  • 187
  • 5
    The ability to specify formatting parameters by position in boost::format() is great for localization. – Ferruccio Jan 07 '10 at 01:57
  • 11
    But `boost::format` gives you such niceties as type safety. `printf` just blows up. – jalf Jan 07 '10 at 10:30
  • 2
    Nice answer. Just want to add that there are alternatives to Boost Format that are several times faster while providing the same level of safety: https://github.com/vitaut/format and https://github.com/c42f/tinyformat – vitaut Feb 23 '13 at 00:05
21

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

Igor Zevaka
  • 74,528
  • 26
  • 112
  • 128
21

Adaptability

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

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.

IO-Streams:

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:

// 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:

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

I18N

We reuse our Person definition:

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.

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. 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!

If you use iostreams consistently, you can

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):

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.

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.

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.

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..

  • 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.

Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
  • 2
    Modern compilers diagnose mismatch between format specs and arguments. – vitaut Feb 23 '13 at 00:14
  • 1
    thank you - that is a very good explanation! @vitaut they cannot in general. for example, if the format spec itself is not a constant string literal but is coming from a configuration file. this is not a hypothetical example, in most commercial software, for 18n and for maintaining consistency of communication, most strings are not in-place literals but compartmentalized not always as literals. – necromancer Mar 28 '13 at 02:49
  • 1
    @agksmehx: Very nice example counter the reliability of format-string checking. – Sebastian Mach Mar 28 '13 at 11:51
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.

janm
  • 17,976
  • 1
  • 43
  • 61
9

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.

Google C++ style guide agrees.

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

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.

cuteCAT
  • 2,251
  • 4
  • 25
  • 30
  • 1
    +1 for the link. It's no 10 Commandments, but they sure have their heads on straight. – ojrac Jan 07 '10 at 05:07
  • 2
    In my opinion while the Google C++ Style Guide is very good in many respects, the consistency trump they refer to is that of their own code. Remember that Google has been around for 10 years, and they value code consistency (a very good thing). The reason they aren't using printf is because people used it in previous incarnations of their code and they want to remain consistent. If this weren't the case I'm confident that they would be using streams instead. – Geoff Mar 12 '10 at 16:59
  • 1
    Huh?! You have precision control with iostreams, too. – Sebastian Mach Feb 09 '12 at 13:17
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.

mingos
  • 23,778
  • 12
  • 70
  • 107
  • 4
    c libraries are very good quality, and easy to use. i agree that people shouldn't feel pressured to use c++ libraries. – Matt Joiner Jan 07 '10 at 01:05
  • 1
    I, too, never had a problem with my hammer. It's simple and robust, and I know what to expect when building a house with it. – Sebastian Mach Aug 23 '13 at 10:40
  • @phresnel, that is correct: hammering nails using a hammer is by far the best choice of tools for the task. Allegedly, rocks work too, but not as well as hammers. – mingos Aug 23 '13 at 20:53
  • @mingos: I prefer houses which are also held together with cement, screws, bolts (but a good hammer can do it). Lifting bricks to the third floor and sawing beams for the rooftop is a bit tough with a hammer, but it works :) I sometimes use C functions too, especially when talking with other software, but for the large part, I prefer when the compiler catches errors for me through strong and static typesafety. That way, if I change some piece somewhere, and do a complete recompile, I get errors everywhere which I can rely on (but that's just the tip of the iceberg of my reasoning). – Sebastian Mach Aug 24 '13 at 20:07
  • @phresnel: Are you implying that a hammer (ie `printf`) is not a tool one should use because it's not good for screwing screws, sawing beams and lifting bricks? Ie, because it sucks at tasks it's not meant for? – mingos Aug 26 '13 at 09:21
  • @mingos: Exactly. But more seriously: You wrote "No reason at all", but actually there _are_ plenty of reasons against it (the only thing I found `printf` better at was saving bytes). And while _you_ may know how to use it right, many people do not (and I remember ungrateful debugging sessions like e.g. when there where triangles in a rasterizer which were flickering on screen, and by accident I found that a misused printf was at fault, at a totally remote place, not even in the same application code) – Sebastian Mach Aug 27 '13 at 06:46
  • 1
    A *misuse* of a function is also not a reason against using it at all :). I'm not advocating the use of `printf` over `cout` (though others do - link in another answer to this question) and I agree there are *cases* where `cout` is clearly a more suitable option. However, I do firmly believe that using `cout` over `printf` just for the sake of it being "the C++ way" is no more than religious bs. – mingos Aug 27 '13 at 08:08
6

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

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.

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
  • 2
    Agreed here. It might seem annoying, but it's always a good idea to compile your code with as many restrictions from the compiler as possible. Enable all warnings, treat all warnings as if they were errors and, if possible, use electric fence + gdb as often as possible. But that's a general coding tip ;) – mingos Jan 07 '10 at 13:05
  • Interestingly xCode IDE detects these things you've mentioned here (in its intellisense.) – bobobobo Aug 02 '10 at 02:43
  • code not always bult in ide or on local system.It not always designed by same party. Format strings are platform dependant (because varables have different sizes on different platforms. In vs 2010 long is 64bit. In gcc it is 32bit. Boom, underrun). But I'm surprised on how few people know that there is standartized header with string literals for proper format strings. – Swift - Friday Pie Apr 24 '18 at 19:06
5

Streams are the canonical way. Try making this code work with 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.

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.

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.

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

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • Yeah I doubt this will work with a `printf` seeing as how templates didn't exist when `printf` was invented. – Bob Dylan Jan 07 '10 at 01:08
  • That's the point. This is C++ code we're talking about, isn't it? Am I being down voted for having a true point? Can the down voters implement my function with `printf`? – GManNickG Jan 07 '10 at 01:09
  • 10
    Your not being downvoted because you have a true point, your being downvoted because your point is irrelevant. We know `printf` can't do this, it's not designed to. It's like saying, "Oh I bet you can't make a class in C". That point would be true as well because the language isn't designed to. – Bob Dylan Jan 07 '10 at 01:17
  • 10
    It's hardly irrelevant. You're asking if you should use `printf`. For consistency, **no**. Streams will always work, `printf` will not always work. Code that isn't consistent is ugly. What if I have `cout` tee'd to also print to a log file? (And yes, all my projects do this!) Now you're just bypassing all that. There's more to think about than you saving keystrokes. – GManNickG Jan 07 '10 at 01:24
  • GMan, I see where you are coming from, but I think the point may be better expressed as 'there is some value in using a consistent output operation'. The OP says he uses both cout and printf, so ultimately the question is whether he should be using just one - as you demonstrate, probably cout - or if it's okay to mix them up. I would say that it's okay, and hope that anyone who can program with cout isn't going to be befuddled by printf(), but I can see how other people might disagree. – Tim Crone Jan 07 '10 at 01:33
  • Consider my usage above. And in programming anyway, consistency is *always* a good thing. – GManNickG Jan 07 '10 at 01:44
  • 1
    So you have to write an overloaded << operator for T, rather than a print(T) function. – Martin Beckett Jan 07 '10 at 02:57
  • Rather than a `print(T, S)` function, actually. S is the output stream. No need for that with `operator<<`; it works on any ostream interface. – GManNickG Jan 07 '10 at 03:17
  • "mixing `cout` and `printf`, while perfectly valid, is ugly" - the only ugly is the `x << y << z` madness! – bobobobo Aug 04 '10 at 20:00
  • __To printf__ an object, there's no problem with defining a member function `object.print( FILE* f )`. You can pass `stdout`, `stderr`, or an already open `FILE*` object to this function. – bobobobo Aug 04 '10 at 20:02
  • 1
    @bobobobo: So you suggest that `printf(stdout, "Hello "); person.print(stdout); printf("! I see you've subscribed to the "); tags.print(stdout); printf("tags, nice!");` is less mad and more pretty than `cout << "Hello " << person << "! I see you've subscribed to the " << tags << ", nice!";`? – Sebastian Mach May 24 '12 at 12:24
  • @bobobobo: Apart from your other (orthogonal wrt topic) suggestion to introduce a pretty tight coupling on the object's public interface. – Sebastian Mach May 24 '12 at 12:26
  • 1
    Your code presumes that `pX` has an operator method for `<<`. If I assume that `pX` has a type method for `(char *)` I can use `printf()` with a `(char *)` cast. That leaves no advantage for `cout`. Personally, I very much dislike the overloaded meaning of the `<<` operator, so I tend to prefer `printf()` or other solutions. – Bill Weinman Apr 02 '14 at 21:23
  • cout only really works if you use a wrapper like tinyformat, otherwise every single cout line becomes a giant jumble of "set output flags, output"... ideally with "reset output flags" on the end. It gets really tedious after a while, and debugging even more so. Wrap or use printf IMO... which takes you back to a print-like situation. – Code Abominator Mar 06 '17 at 00:34
5

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::print("The answer is {}.", 42);

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

Disclaimer: I'm the author of this library.

vitaut
  • 49,672
  • 25
  • 199
  • 336
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.

Share and enjoy.

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);

Here's the header (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):

#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!

Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
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++.

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

Paul Nathan
  • 39,638
  • 28
  • 112
  • 212
1

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

Printing user-created objects with printf()

This is rather simple if you think about it - you can stringify your type and sent the string to 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...

printf() pitfall

A single flag - %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).

milleniumbug
  • 15,379
  • 3
  • 47
  • 71
  • I am afraid that is not an extension to the `printf` interface. It would have been if you could now write `printf("%[MyClass] is awesome, my_object")`. – Sebastian Mach Jan 22 '13 at 11:02
  • @phresnel I agree. This is only to say that it IS possible to print user-created objects with printf. It is a workaround, yes, but so is operator chaining workaround to lack of real vararg function capability in pre-C++11. C++ I/O library created now would be probably using initializer_list or variable-length template functions. – milleniumbug Jan 22 '13 at 13:19
  • Though operator chaining is part of the iostreams interface, and the possibility to extend that interface is part of the interface, too, so it still holds true that iostreams are extensible, whereas printf is not. This is what I liked to point out :) – Sebastian Mach Jan 22 '13 at 13:31
  • I agree on how probably variadic templates would now be used if a new io-library would become part of C++. – Sebastian Mach Jan 22 '13 at 13:32
  • @phresnel Changed the wording in the answer. – milleniumbug Jan 22 '13 at 13:50
  • I think it's better now :) – Sebastian Mach Jan 22 '13 at 15:25
  • Downvoting without any comment is hardly constructive, as I have no opportunity to learn from my mistakes. Downvoter, could you explain the downvote? – milleniumbug Aug 23 '13 at 11:43
1

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.

Oleg Shalaev
  • 159
  • 1
  • 5
1

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.

aib
  • 45,516
  • 10
  • 73
  • 79
1

(See the fmt library homepage)

In C++20, the fmt library is standardized for the formatting part:

std::format("({},{})\n", x, y) // returns a std::string

You can avoid the dynamic allocation overhead by using format_to:

std::format_to(/* output iterator */, "({},{})\n", x, y);

This should be considered the canonical way of formatting because it combines the benefits of streams:

  • Safety: the library is fully type safe. Automatic memory management prevents buffer overflow. Errors in format strings are reported using exceptions or at compile time.

  • Extensibility: overloading operator<< is easy, whereas extending printf is ... not so easy.

and that of printf:

  • Ease to use: the % syntax is supported rather than the verbose manipulators. The {} syntax is also introduced to eliminate the specifiers.

  • Performance: measurement has shown that the fmt library is so far the fastest output method in C++. Faster than printf and streams.

L. F.
  • 19,445
  • 8
  • 48
  • 82
1

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.

Petruza
  • 11,744
  • 25
  • 84
  • 136
  • 1
    Not only have you to match the placeholders _now_, but also in future. See my updated post, section _Temporal Adaptibility_, and the other sections of course. – Sebastian Mach May 24 '12 at 12:11
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.

quantum
  • 3,672
  • 29
  • 51
-1

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

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

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

its more of a personal choice.

ishan
  • 301
  • 2
  • 9
  • 2
    Using C++ doesn't mean you have to object-orient everything, and particularly console printing is not something that really calls for the OO paradigm. – Petruza Dec 03 '11 at 16:42