cpp-salida-consola-printf-print

Console Output in C++: From printf to std::print

  • 5 min

Console output in C++ is the basic way to display information to the user from a program, whether to show results, debug, or simply verify that something is working.

When starting out, it’s normal to use std::cout, but several ways of printing text coexist in C++: printf, std::cout, std::format, and std::print. Each has its place, its advantages, and its little pitfalls.

In this article, we’ll look at the old familiar printf, the classic std::cout stream, and the modern alternatives std::format and std::print.

Quick Comparison

Featureprintfstd::coutstd::formatstd::print
StandardC / C++C++98C++20C++23
Type safetyLowHighHighHigh
SyntaxCompactVerboseModernModern
Prints directlyYesYesNoYes
Typical useC, legacy, embeddedClassic C++Formatting stringsModern console

The Classic: printf

printf (print formatted) comes from the C language and is available in C++ through the <cstdio> header. Despite being quite old, it remains very common in legacy code, embedded systems, and quick examples.

It works based on a format string that contains text and placeholders starting with %. Then we pass the values that fill those placeholders.

#include <cstdio>

int main() {
    int age = 35;
    double height = 1.75;

    printf("I am %d years old and %.2f meters tall\n", age, height);
}
Copied!

Notice it’s quite compact. The major drawback is that printf does not check types with the same safety as modern C++ tools.

Common Specifiers

To use printf, we need to know the format specifiers. If we make a mistake, the program can print garbage or exhibit undefined behavior (and that’s never a fun afternoon).

SpecifierCommon TypeExample
%d or %iSigned integer (int)10, -5
%uUnsigned integer (unsigned int)20
%fFloating point (float, double)3.14159
%cCharacter (char)'A'
%sC-style string (const char*)"Hello"
%x / %XHexadecimalfa, FA
%pPointermemory address

Beware of std::string

printf does not understand C++ objects like std::string. It expects C strings, that is, const char* pointers.

#include <cstdio>
#include <string>

int main() {
    std::string name = "Luis";

    // Incorrect: printf expects const char*, not std::string
    // printf("Hello %s\n", name);

    // Correct
    printf("Hello %s\n", name.c_str());
}
Copied!

If you use printf with C++ types, explicitly convert them to types that C can understand. With std::string, that means using .c_str().

std::cout

std::cout lives in <iostream> and is the classic C++ way to write to the console. It uses the << operator, just like we saw in the early examples of the course.

#include <iostream>
#include <string>

int main() {
    std::string name = "Luis";
    int age = 35;

    std::cout << "Hello " << name << ", you are " << age << " years old.\n";
}
Copied!

The advantage of std::cout is that it works well with C++ types and avoids many typical printf errors. The disadvantage is that when there is a lot of formatting, it can become quite verbose.

std::format

C++20 introduced std::format, which allows creating formatted strings using {} as placeholders. It closely resembles the style of Python or other modern formatting libraries.

#include <format>
#include <iostream>
#include <string>

int main() {
    std::string name = "Luis";
    int age = 35;

    std::string text = std::format("Hello {}, you are {} years old.", name, age);
    std::cout << text << "\n";
}
Copied!

std::format does not print directly. It returns a std::string, which you can then store, send to a log, write to a file, or display on the console.

std::print and std::println

C++23 adds std::print and std::println, which are the direct version for printing using the same formatting system.

#include <print>
#include <string>

int main() {
    std::string name = "Luis";
    int age = 35;

    std::println("Hello {}, you are {} years old.", name, age);
}
Copied!

The difference is simple:

  • std::print does not add a newline.
  • std::println adds a newline at the end.

std::print belongs to C++23, so its availability depends on the compiler and the standard library you use. If your environment doesn’t support it yet, std::format + std::cout is a reasonable alternative.

Advanced Formatting

Inside the braces, we can add format specifiers. For example, for decimals or hexadecimal:

double pi = 3.14159265;
int color = 255;

std::println("Pi is {:.2f} and the color is {:X}", pi, color);
Copied!

In this example, {:.2f} shows two decimal places and {:X} shows the integer in hexadecimal with uppercase letters.