La salida por consola en C++ es la forma básica de mostrar información al usuario desde un programa, ya sea para enseñar resultados, depurar o simplemente comprobar que algo está funcionando.
Lo normal al empezar es usar std::cout, pero en C++ conviven varias formas de imprimir texto: printf, std::cout, std::format y std::print. Cada una tiene su sitio, sus ventajas y sus pequeñas trampas.
En este artículo vamos a ver al viejo conocido printf, el flujo clásico std::cout, y las alternativas modernas std::format y std::print.
Comparativa rápida
| Característica | printf | std::cout | std::format | std::print |
|---|---|---|---|---|
| Estándar | C / C++ | C++98 | C++20 | C++23 |
| Seguridad de tipos | Baja | Alta | Alta | Alta |
| Sintaxis | Compacta | Verbosa | Moderna | Moderna |
| Imprime directamente | Sí | Sí | No | Sí |
| Uso típico | C, legacy, embebidos | C++ clásico | Formatear cadenas | Consola moderna |
El clásico: printf
printf (print formatted) viene del lenguaje C y está disponible en C++ a través de la cabecera <cstdio>. A pesar de tener ya unos cuantos años encima, sigue siendo muy habitual en código legacy, sistemas embebidos y ejemplos rápidos.
Su funcionamiento se basa en una cadena de formato que contiene texto y huecos que empiezan por %. Después pasamos los valores que rellenan esos huecos.
#include <cstdio>
int main() {
int edad = 35;
double altura = 1.75;
printf("Tengo %d años y mido %.2f metros\n", edad, altura);
}Fíjate en que queda bastante compacto. La pega es importante: printf no comprueba los tipos con la misma seguridad que las herramientas modernas de C++.
Especificadores habituales
Para usar printf, necesitamos conocer los especificadores de formato. Si nos equivocamos, el programa puede imprimir basura o comportarse de forma indefinida (y eso nunca es una tarde divertida).
| Especificador | Tipo habitual | Ejemplo |
|---|---|---|
%d o %i | Entero con signo (int) | 10, -5 |
%u | Entero sin signo (unsigned int) | 20 |
%f | Flotante (float, double) | 3.14159 |
%c | Carácter (char) | 'A' |
%s | Cadena estilo C (const char*) | "Hola" |
%x / %X | Hexadecimal | fa, FA |
%p | Puntero | dirección de memoria |
Cuidado con std::string
printf no entiende objetos C++ como std::string. Espera cadenas de C, es decir, punteros const char*.
#include <cstdio>
#include <string>
int main() {
std::string nombre = "Luis";
// Incorrecto: printf espera const char*, no std::string
// printf("Hola %s\n", nombre);
// Correcto
printf("Hola %s\n", nombre.c_str());
}Si usas printf con tipos de C++, convierte explícitamente a tipos que C pueda entender. Con std::string, eso significa usar .c_str().
std::cout
std::cout vive en <iostream> y es la forma clásica de C++ para escribir por consola. Usa el operador <<, igual que vimos en los primeros ejemplos del curso.
#include <iostream>
#include <string>
int main() {
std::string nombre = "Luis";
int edad = 35;
std::cout << "Hola " << nombre << ", tienes " << edad << " años.\n";
}La ventaja de std::cout es que trabaja bien con tipos de C++ y evita muchos errores típicos de printf. La desventaja es que, cuando hay mucho formato, puede quedarse bastante verboso.
std::format
C++20 introdujo std::format, que permite crear cadenas formateadas usando {} como marcadores. Se parece mucho al estilo de Python o de otras librerías modernas de formato.
#include <format>
#include <iostream>
#include <string>
int main() {
std::string nombre = "Luis";
int edad = 35;
std::string texto = std::format("Hola {}, tienes {} años.", nombre, edad);
std::cout << texto << "\n";
}std::format no imprime directamente. Devuelve un std::string, que luego puedes guardar, enviar a un log, escribir en un archivo o mostrar por consola.
std::print y std::println
C++23 añade std::print y std::println, que son la versión directa para imprimir usando el mismo sistema de formato.
#include <print>
#include <string>
int main() {
std::string nombre = "Luis";
int edad = 35;
std::println("Hola {}, tienes {} años.", nombre, edad);
}La diferencia es sencilla:
std::printno añade salto de línea.std::printlnañade un salto de línea al final.
std::print pertenece a C++23, así que su disponibilidad depende del compilador y de la librería estándar que uses. Si tu entorno todavía no lo soporta, std::format + std::cout es una alternativa razonable.
Formato avanzado
Dentro de las llaves podemos añadir especificadores de formato. Por ejemplo, para decimales o hexadecimal:
double pi = 3.14159265;
int color = 255;
std::println("Pi vale {:.2f} y el color es {:X}", pi, color);En este ejemplo, {:.2f} muestra dos decimales y {:X} muestra el entero en hexadecimal con letras mayúsculas.