Quantcast
Channel: 'printf' vs. 'cout' in C++ - Stack Overflow
Viewing all articles
Browse latest Browse all 19

Answer by vitaut for 'printf' vs. 'cout' in C++

$
0
0

API

printf uses a replacement-based API with placeholders starting with % replaced with formatted arguments:

printf("The answer is %d.\n", answer);

cout or, more generally, ostreams use a concatenation-based API with parts of a formatted message interleaved with arguments:

std::cout << "The answer is " << answer << ".\n";

A replacement-based API with proper synchronization provides atomicity, e.g. when writing from multiple threads different messages written with printf won't interleave while parts of the messages written with cout may interleave. For this reason C++20 introduced std::osyncstream which is a clunky way of achieving atomicity.

With operator overloading formatting can quickly become cumbersome, e.g.

std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";

vs

printf("%.2f\n", 1.23456);

Matthew Wilson, the author of FastFormat, called this "chevron hell".

Extensibility

cout supports formatting of user-defined types through overloading of operator<<. There is no standard way to do the same with printf, although there is a glibc extension which is rarely used in practice.

Safety

printf uses varargs which are inherently unsafe unless you use something like GCC's format attribute which only works with literal format strings. It is a user's responsibility to correctly pass type information via format specifiers. Any mismatch results in an undefined behavior and is a common source of vulnerabilities.

cout/ostreams are type-safe and the user doesn't need to manually handle type information.

Buffering

cout adds another layer of buffering and synchronizes with the underlying C streams by default. This brings significant performance overhead. It is possible to disable this synchronization at the cost of worse interoperability with C and potentially other languages.

Formatting state

In printf formatting is controlled via a format string and decoupled from the stream itself. In cout/ostreams the formatting state is stored in the stream which may negatively affect performance and cause unexpected results. Quoting N4412: Shortcomings of iostreams:

Formatting parameters (such as uppercase/lowercase and radix) are specified by setting flags, which mostly persist for an arbitrary number of subsequent low-level formatting operations, until explicitly changed. This approach inhibits compile-time checks and compile-time choice of formatting, and potentially establishes state shared between threads (which requires synchronization for access).

Locales

printf uses the global C locale.

cout uses the C++ locale associated with the stream.

Both printf and cout use locales by default.

Performance

cout is often slower than printf for reasons mentioned above: extra buffering and synchronization (can be disabled) and stateful API.

Language

printf is a part of the C standard library and can be used in C and C++. cout is a part of the C++ standard library and can only be used in C++.


You can have the best of both worlds by using C++23 std::print. It provides a replacement-based API with positional arguments. It is extensible, type-safe, doesn't introduce extra buffering and makes localized formatting an opt-in.

Disclaimer: I'm the author of C++23 std::print.


Viewing all articles
Browse latest Browse all 19

Trending Articles





<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>