Articulo de referencia

imprimirf

Un ejemplo de llamada a la función printf `printf` es una función de la biblioteca estándar de C y también uncomando de terminal (shell) de Linux que formatea texto y lo escribe...

Diagrama que ilustra la sintaxis de la función printf. El primer argumento es una cadena de plantilla que puede contener especificadores de formato, introducidos con el signo de porcentaje (%). Estos especificadores indican a printf cómo interpretar y mostrar los valores de los argumentos que siguen a la cadena de formato. printf reemplaza los especificadores de formato con el contenido de los argumentos restantes, interpretado según corresponda, y muestra el resultado.
Un ejemplo de llamada a la función printf

`printf` es una función de la biblioteca estándar de C y también uncomando de terminal (shell) de Linux que formatea texto y lo escribe en la salida estándar . La función acepta un argumento de cadena de C con formato y un número variable de argumentos de valor que serializa según la cadena de formato. Una discrepancia entre los especificadores de formato y la cantidad y el tipo de valores puede provocar un comportamiento indefinido , y el programa podría fallar opresentar vulnerabilidades .

La cadena de formato se codifica como un lenguaje de plantillas que consta de texto literal y especificadores de formato , cada uno de los cuales indica cómo serializar un valor. A medida que la cadena de formato se procesa de izquierda a derecha, se utiliza un valor subsiguiente para cada especificador de formato encontrado. Un especificador de formato comienza con un %carácter y tiene uno o más caracteres a continuación que indican cómo serializar un valor.

La biblioteca estándar proporciona otras funciones similares que conforman una familia de funciones tipo printf . Estas funciones comparten las mismas capacidades de formato, pero ofrecen un comportamiento diferente, como la salida a un destino distinto o medidas de seguridad que limitan la exposición a vulnerabilidades. Las funciones de la familia printf se han implementado en otros contextos de programación (es decir, lenguajes de programación ) con la misma sintaxis y semántica , o similares .

La función scanf() de la biblioteca estándar de C complementa printf al proporcionar entrada formateada (también conocida como análisis léxico o análisis sintáctico ) a través de una sintaxis de cadena de formato similar.

El nombre printf es la abreviatura de print formatted (imprimir con formato) , donde print se refiere a la salida a una impresora , aunque la función no se limita a la salida a la impresora. Hoy en día, print se refiere a la salida a cualquier entorno basado en texto, como una terminal o un archivo .

Historia

Década de 1950: Fortran

Los lenguajes de programación antiguos, como Fortran, utilizaban instrucciones especiales con una sintaxis diferente a la de otros cálculos para construir descripciones de formato. [ 1 ] En este ejemplo, el formato se especifica en la línea601y el comando PRINT[ a ] se refiere a él por número de línea:

IMPRIMIR 601 , IA , IB , ÁREA 601 FORMATO ( 4 H A = , I5 , 5 H B = , I5 , 8 H ÁREA = , F10.2 , 13 H UNIDADES CUADRADAS )

Por la presente:

Una salida con los argumentos de entrada 100, 200, y 1500.25podría verse así:

A= 100 B= 200 ÁREA= 1500.25 UNIDADES CUADRADAS

Década de 1960: BCPL y ALGOL 68

En 1967 apareció BCPL . [ 2 ] Su biblioteca incluía la writefrutina que parecía una llamada a función cualquiera. [ 3 ] Un ejemplo de aplicación se ve así:

ESCRIBIR("%I2-EL PROBLEMA DE LAS REINAS TIENE %I5 SOLUCIONES*N", NUMREINAS, CONTAR) 

Por la presente:

  • %I2indica un número entero de ancho 2 (el orden del ancho y el tipo de campo de la especificación de formato está invertido en comparación con el de C printf);
  • %I5indica un número entero de ancho 5;
  • *Nes una secuencia de escape del lenguaje BCPL que representa un carácter de nueva línea (para el cual C utiliza la secuencia de escape ).\n

ALGOL 68 también tenía una API de funciones, pero utilizaba una sintaxis especial para el formato:

printf (( $ "Color " g ", número1 " 6 d , ", número2 " 4 zd , ", hex " 16 r2d , ", flotante " - d .2 d , ", valor sin signo " -3 d "." l$ , "rojo" , 123456 , 89 , BIN 255 , 3.14 , 250 ));

El uso de la sintaxis de función normal para la impresión simplifica el lenguaje y permite implementar la impresión en el propio lenguaje. En la mayoría de los lenguajes más recientes de esa época, la entrada/salida no forma parte de la sintaxis. Sin embargo, el formato generalmente no se verificaba para comprobar si coincidía con el tipo (o incluso la cantidad) de valores que se imprimían. [ 4 ]

Década de 1970: C

En 1973, printfse incluyó como una rutina de la biblioteca estándar de C como parte de la versión 4 de Unix . [ 5 ]

Década de 1990: Comando de shell

En 1990, el comando printfde shell , modelado a partir de la función de la biblioteca estándar de C, se incluyó con 4.3BSD-Reno . [ 6 ] En 1991, se incluyó un comando con GNU shellutils (ahora parte de GNU Core Utilities ) y la sintaxis (opciones, argumentos, etc.) de este " comando de shell " es diferente de la función del lenguaje C, por ejemplo: la "sección de formato" no utiliza los argumentos posicionales [ 7 ] con un símbolo "$" (n$) de la misma manera que la función:printfprintf()

str = "AA BB CC" # cadena simple con 3 camposestablecer -- $str # convertir campos en parámetros posicionalesprintf "%s " $2 $3 $1 ; echo # en C printf() usa 2$ 3$..# impresiones: BB CC AA

Década de 2000: Java

En 2004, se lanzó Java 5.0 (1.5), que extendió la clase java.io.PrintStream, agregando un método llamado printf()que funciona de manera análoga a printf()en C. Así, para imprimir una cadena formateada en el flujo de salida estándar, se usa System.out.printf(). Java introdujo además el método formaten su clase de cadena java.lang.String. [ 8 ]

Década de 2000: -Seguridad de formato W

La necesidad de abordar la variedad de problemas derivados de la falta de seguridad de tipos ha impulsado intentos de lograr que los compiladores printfsean conscientes de ello.

La -Wformatopción de GNU Compiler Collection (GCC) permite realizar comprobaciones en tiempo de compilación de printflas llamadas, lo que permite al compilador detectar un subconjunto de llamadas no válidas (y emitir una advertencia o un error, terminando la compilación, según lo establecido por otras banderas). [ 9 ]

Dado que el compilador inspecciona printflos especificadores de formato, esta característica extiende de forma efectiva el análisis estático en C para incluir aspectos de formato.

Década de 2020: std::print

C++ añadió soporte para entrada/salida mediante el operador << para evitar problemas de seguridad con printf. [ 10 ] Este operador utilizaba el tipo de los argumentos para determinar qué código ejecutar para imprimirlos, evitando así los fallos que pueden producirse con las cadenas de formato. Sin embargo, la sintaxis puede resultar extensa (sobre todo para configurar opciones como la precisión), y printf sigue estando disponible en C++ y se suele utilizar en su lugar.

C++20 agregó una nueva API que utiliza una cadena que consta de texto literal y marcadores de posición seguidos de los valores a imprimir. [ 11 ] La cadena de formato utiliza llaves en lugar de signos de porcentaje, basándose en la sintaxis utilizada en la biblioteca estándar de Python : [ 11 ] [ 12 ]

std::format("The hex value of {} is {:x}.",name,value)

La implementación recomendada es la de fmtlib de Victor Zverovich [ 11 ] [ 13 ] , que en tiempo de compilación convierte los tipos de cadena y argumento en un objeto de formato optimizado; esto es seguro en cuanto a tipos y los errores de sintaxis se detectan en tiempo de compilación. C++23 introdujo las funciones y que combinaban formato y salida, y por lo tanto es un reemplazo funcional para . [ 14 ] Es posible crear un traductor de una cadena % de printf al mismo objeto de formato [ 15 ] y esto podría producir un printf seguro en cuanto a tipos , pero esto tampoco se agregó a la especificación. No se ha introducido ninguna modernización análoga de scanf , aunque se ha propuesto una basada en scnlib . [ 16 ]std::print()std::println()printf() 

Estas funciones (más std::to_chars) pueden imprimir números de coma flotante con precisión utilizando la menor cantidad posible de dígitos finales, una capacidad que printf no tenía desde hace mucho tiempo . Otra característica útil es que ignoran la configuración regional .

especificador de formato

El formato de un valor se especifica como marcado en la cadena de formato. Por ejemplo, la siguiente salida Your age ismuestra el valor de la variable edad en formato decimal.

printf ( "Tu edad es %d" , edad );

Sintaxis

La sintaxis para un especificador de formato es:

%[ parámetro ][ indicadores ][ ancho ][. precisión ][ longitud ] tipo

Campo de parámetros

El campo de parámetros es opcional. Si se incluye, la correspondencia entre especificadores y valores no es secuencial. El valor numériconorteselecciona el enésimo parámetro de valor. Esta es una extensión POSIX , no C99 .

Este campo permite usar el mismo valor varias veces en una cadena de formato, en lugar de tener que pasarlo varias veces. Si un especificador incluye este campo, los especificadores subsiguientes también deben incluirlo.

Por ejemplo,

printf ( "%2$d %2$#x; %1$d %1$#x" , 16 , 17 );

Salidas:17 0x11; 16 0x10

Este campo es muy útil para localizar mensajes a diferentes idiomas naturales que utilizan diferentes órdenes de palabras .

En la API de Windows , la compatibilidad con esta característica se realiza a través de una función diferente printf_p.

Campo de banderas

El campo de indicadores puede contener cero o más de los siguientes elementos (en cualquier orden):

Campo de ancho

El campo de ancho especifica el número mínimo de caracteres que se mostrarán. Si el valor se puede representar con menos caracteres, se rellena con espacios a la izquierda para que la salida tenga el número de caracteres especificado. Si el valor requiere más caracteres, la salida será más larga que el ancho especificado. Un valor nunca se trunca.

Por ejemplo, especifica un ancho de 3 y generaprintf("%3d",12);12con un espacio a la izquierda para generar 3 caracteres. La llamada generaprintf("%3d",1234);1234que tiene 4 caracteres de longitud, ya que ese es el ancho mínimo para ese valor, aunque el ancho especificado sea 3.

Si se omite el campo de ancho, el resultado será el número mínimo de caracteres para el valor.

Si el campo se especifica como *, entonces el valor del ancho se lee de la lista de valores en la llamada. [ 17 ] Por ejemplo, las salidasprintf("%*d",3,10);10(<espacio>10) donde el segundo parámetro, 3, es el ancho (coincide con *) y 10es el valor a serializar (coincide con d).

Aunque no forma parte del campo de ancho, un cero inicial se interpreta como el indicador de relleno de ceros mencionado anteriormente, y un valor negativo se trata como el valor positivo junto con el -indicador de alineación a la izquierda también mencionado anteriormente.

El campo de ancho se puede utilizar para formatear valores como una tabla (salida tabulada). Pero las columnas no se alinean si algún valor es mayor que el ancho especificado. Por ejemplo, observe que el último valor de la línea (1234) no cabe en la primera columna de ancho 3 y por lo tanto la columna no está alineada.

 1 1 12 12 123 123 1234 123

Campo de precisión

El campo de precisión generalmente especifica un límite máximo para la salida, según lo define el tipo de formato. Para los tipos numéricos de punto flotante , especifica la cantidad de dígitos a la derecha del punto decimal a los que se debe redondear la salida; para %gy %Gespecifica la cantidad total de cifras significativas (antes y después del punto decimal, sin incluir los ceros iniciales o finales) a las que se debe redondear. Para el tipo de cadena , limita la cantidad de caracteres que se deben mostrar, después de lo cual la cadena se trunca.

El campo de precisión puede omitirse, o ser un valor numérico entero, o un valor dinámico cuando se pasa como otro argumento cuando se indica con un asterisco ( *). Por ejemplo, las salidasprintf("%.*s",3,"abcdef");abecedario.

Campo de longitud

El campo de longitud puede omitirse o ser cualquiera de los siguientes:

Las opciones de longitud específicas de cada plataforma surgieron antes del uso generalizado de las extensiones ISO C99, entre las que se incluyen:

ISO C99 incluye el inttypes.harchivo de cabecera que contiene varias macros para la codificación multiplataformaprintf . Por ejemplo: especifica el formato decimal para un entero con signo de 64 bits . Dado que las macros se evalúan como una cadena literal y el compilador concatena cadenas literales adyacentes, la expresión se compila en una sola cadena.printf("%"PRId64,t);"%"PRId64

Las macros incluyen:

Campo de tipo

El campo de tipo puede ser cualquiera de los siguientes:

Formato de tipo de datos personalizado

Una forma común de manejar el formato con un tipo de datos personalizado es formatear el valor del tipo de datos personalizado en una cadena y luego usar el especificador para incluir el valor serializado en un mensaje más extenso.%s

Algunas funciones tipo printf permiten extensiones al minilenguaje basado en caracteres de escape , lo que permite al programador usar una función de formato específica para tipos no integrados. Una de ellas es la función de glibc (ahora obsoleta ) . Sin embargo, rara vez se usa debido a que entra en conflicto con la comprobación estática de cadenas de formato . Otra es la función de formateo personalizado Vstr , que permite agregar nombres de formato de varios caracteres.register_printf_function()

Algunas aplicaciones (como el servidor HTTP Apache ) incluyen su propia función similar a printf e incorporan extensiones en ella. Sin embargo, todas tienden a tener los mismos problemas que register_printf_function()tiene.

La función del kernel de Linuxprintk admite varias formas de mostrar estructuras del kernel utilizando la especificación genérica, agregando caracteres de formato adicionales. [ 21 ] Por ejemplo, imprime una dirección IPv4 en formato decimal con puntos. Esto permite la comprobación estática de la cadena de formato (de la porción) a costa de la compatibilidad total con printf normal.%p%pI4%p

Vulnerabilidades

Ataque de cadena de formato

Los argumentos de valor adicionales se ignoran, pero si la cadena de formato tiene más especificadores de formato que argumentos de valor pasados, el comportamiento es indefinido. Para algunos compiladores de C, un especificador de formato adicional provoca el consumo de un valor aunque no exista, lo que permite el ataque de cadena de formato . Generalmente, en C, los argumentos se pasan en la pila . Si se pasan muy pocos argumentos, printf puede leer más allá del final del marco de pila, lo que permite a un atacante leer la pila.

Algunos compiladores, como la Colección de Compiladores GNU , comprueban estáticamente las cadenas de formato de las funciones tipo printf y advierten sobre posibles problemas (al usar las opciones o ). GCC también advierte sobre las funciones de estilo printf definidas por el usuario si se aplica el formato no estándar "format" a la función.-Wall-Wformat__attribute__

Explotación de cadena de formato no controlada

La cadena de formato suele ser una cadena literal , lo que permite un análisis estático de la llamada a la función. Sin embargo, también puede ser el valor de una variable , lo que permite un formato dinámico, pero también una vulnerabilidad de seguridad conocida como explotación de cadena de formato no controlada .

Escritura en memoria

Aunque superficialmente es una función de salida, printfpermite escribir en una ubicación de memoria especificada por un argumento a través de . Esta funcionalidad puede utilizarse para ataques de inyección de código sin violar la integridad del flujo de control . [ 22 ]%n

El especificador de formato también hace que sea accidentalmente Turing-completo incluso con un conjunto de argumentos bien formado. [ 22 ] Un juego de tres en raya escrito en la cadena de formato es ganador del 27.º IOCCC . [ 23 ]%nprintf

Familia

Las variantes de printfla biblioteca estándar de C incluyen: fprintfsalida a un archivo en lugar de la salida estándar.

sprintfEscribe en un búfer de cadena en lugar de en la salida estándar.

snprintfproporciona un nivel de seguridad sprintfya que quien llama proporciona una longitud n que es la longitud del búfer de salida en bytes (incluido el espacio para el carácter nulo final).

asprintfProporciona seguridad al aceptar un argumento de identificador de cadena ( char**). La función asigna un búfer de tamaño suficiente para contener el texto formateado y lo envía a través del identificador.

Para cada función de la familia, incluyendo printf, también hay una variante que acepta un solo va_listargumento en lugar de una lista variable de argumentos. Normalmente, estas variantes comienzan con "v". Por ejemplo: vprintf, vfprintf, vsprintf.

Generalmente, las funciones tipo printf devuelven el número de bytes de salida o -1 para indicar un fallo. [ 24 ]

Otros contextos

La siguiente lista incluye lenguajes de programación destacados que proporcionan (directamente o a través de una biblioteca estándar) funcionalidades iguales o similares a las funciones printf de C. Se excluyen los lenguajes que utilizan cadenas de formato que se desvían del estilo descrito en este artículo (como AMPL y Elixir ), los lenguajes que heredan su implementación de la máquina virtual de Java (JVM) u otro entorno (como Clojure y Scala ), y los lenguajes que no tienen una implementación nativa estándar de printf, pero que cuentan con bibliotecas externas que emulan su comportamiento (como JavaScript ).

Véase también

  • Programa "Hello, World!" Un programa de ejemplo básico que apareció por primera vez en El lenguaje de programación C (el "Libro K&R"), que en el ejemplo de C usa printf para mostrar el mensaje "Hello, World!" 
  • Formatear (Common Lisp) – Función de Common Lisp que produce texto formateado 
  • Biblioteca estándar de C : biblioteca estándar para el lenguaje de programación C. 
  • Ataque de formato de cadena : tipo de vulnerabilidad de software. Páginas que muestran descripciones breves de objetivos de redirección. 
  • Entrada/salida (C++) – Funcionalidad de entrada/salida de C++ en la biblioteca estándar Páginas que muestran descripciones breves de los destinos de redirección 
  • Depuración de printf : corrección de defectos en un sistema diseñado. Páginas que muestran descripciones breves de los destinos de redirección. 
  • printf (Unix) – Comando de shell para formatear y mostrar texto; similar a la función de biblioteca printf(). 
  • printk – Función similar a printf para el kernel de Linux 
  • scanf – Parámetro de control utilizado en lenguajes de programación 
  • interpolación de cadenas : reemplazar marcadores de posición en una cadena con valores. 

Notas

  1. Según el manual de Fortran de 1956 [ 1 ] , elPRINTcomando imprime en la impresora conectada . El manual también introduce el comandoque también utiliza lainstrucción para escribir en una unidad de cinta .WRITE OUTPUTTAPEFORMAT

Referencias

  1. 1 2 Backus, John Warner ; Beeber, RJ; Best, Sheldon F.; Goldberg, Richard; Herrick, Harlan L.; Hughes, RA; Mitchell, LB; Nelson, Robert A.; Nutt, Roy ; Sayre, David ; Sheridan, Peter B.; Stern, Harold; Ziller, Irving (15 de octubre de 1956). Sayre, David (ed.). El sistema de codificación automática FORTRAN para el IBM 704 EDPM: Manual de referencia del programador (PDF) . Nueva York, EE. UU.: División de Ciencias Aplicadas y Departamento de Investigación de Programación, International Business Machines Corporation . págs. 26–30 . Archivado (PDF) del original el 4 de julio de 2022. Recuperado el 4 de julio de 2022 . (2+51+1 páginas)
  2. "BCPL" . cl.cam.ac.uk. Consultado el 19 de marzo de 2018 .
  3. Richards, Martin; Whitby-Strevens, Colin (1979). BCPL - el lenguaje y su compilador . Cambridge University Press. pág. 50 . 
  4. "Ataque de formato de cadena" .
  5. McIlroy, MD (1987). Un lector de Research Unix: extractos anotados del Manual del programador, 1971–1986 (PDF) (Informe técnico). CSTR. Bell Labs. 139.
  6. "printf (4.3+Reno BSD)" . man.freebsd.org . Consultado el 1 de abril de 2024 .
  7. "Parámetros de posición" . tldp.org . Consultado el 16 de diciembre de 2025 .
  8. "Clase PrintStream" . docs.oracle.com . Consultado el 13 de septiembre de 2025 .
  9. "3.8 Opciones para solicitar o suprimir advertencias" . Manual de GCC 14.2 . Free Software Foundation . 2024. Consultado el 12 de febrero de 2025 .
  10. Stroustrup, Bjarne (marzo de 1993). "Una historia de C++: 1979–1991" . ACM SIGPLAN Notices . 28 (3). Association for Computing Machinery : 271–297 . doi : 10.1145/155360.155375 . ISSN 0362-1340 . 
  11. 1 2 3 Collyer, Spencer (diciembre de 2021). "Formato de texto en C++20: una introducción" . Overload . 29 (166). Reino Unido: ACCU : 9–21 . ISSN 1354-3172 . Wikidata Q140407206 .  
  12. Bancila, Marius (2020). "Trabajando con números y cadenas" . Modern C++ Programming Cookbook (2.ª ed.). Packt. ISBN  978-1-8002-0620-5.
  13. Zverovich, Victor (16 de julio de 2019). "Formato de texto" . Documentos del Comité de Estándares de C++. Estándares abiertos.
  14. Kusswurm, Daniel (noviembre de 2024). "E/S formateada" . Programación práctica en C++ STL . Berkeley, California: Apress . págs. 63–103 . ISBN  979-8-8688-0774-9.
  15. "Imprimir de forma segura" .
  16. Kosunen, E.; Zverovich, V. (15 de octubre de 2024). "P1729R5: Análisis sintáctico de texto" . Documentos del Comité de Estándares de C++. Estándares abiertos.
  17. "printf" . cplusplus.com . Consultado el 10 de junio de 2020 .
  18. "7.19.6.1". ISO/IEC 9899:1999(E): Lenguajes de programación – C (Informe técnico). ISO / IEC . 1999. párr. 7.
  19. ^ Gustedt, Jens (15 de octubre de 2024). "Funciones de la biblioteca C". C moderna . Inria. pag. 120.ISBN  9781617295812.
  20. Schildt, H.; Coward, D. (2024). "java.util Parte 2: Más clases de utilidad". En Ritter, S. (ed.). Java: La referencia completa (13.ª ed.). McGraw Hill. págs. 667–726 . ISBN   978-1-265-05843-2.
  21. Dunlap, Randy; Murray, Andrew (s.f.). "Cómo configurar correctamente los especificadores de formato de printk". Documentación del kernel de Linux (Informe). Linux Foundation . Archivado del original el 6 de febrero de 2025. Consultado el 12 de febrero de 2025 .
  22. 1 2 Carlini, N.; Barresi, A.; Payer, M.; Wagner, D.; Gross, TR (12 de agosto de 2015). "Control-flow bending: on the effectiveness of control-flow integrity" (PDF) . Actas del 24.º Simposio de la Conferencia USENIX sobre Seguridad . SEC'15. Washington, DC: USENIX . págs. 161–176 . ISBN  978-1-931971-23-2. S2CID 2165728 . 
  23. Carlini, Nicholas (2020). "Máquina printf" . Concurso Internacional de Código C Ofuscado . Jueces: Leonid A. Broukhis, Landon Curt Noll. Landon Curt Noll . Recuperado el 12 de febrero de 2025 .
  24. Kerrisk, Michael (2 de febrero de 2025). "sprintf(3) — Página del manual de Linux" . man7.org . Consultado el 19 de marzo de 2025 .
  25. "POSIX awk, Instrucciones de salida". Especificaciones básicas de The Open Group, número 7. pubs.opengroup.org ( Informe técnico) ( ed. 2018). The Open Group . Consultado el 29 de mayo de 2022 . 
  26. "Biblioteca estándar Printf" . El manual del lenguaje Julia . Consultado el 22 de febrero de 2021 .
  27. "Tipos integrados: formato de cadena estilo" , La biblioteca estándar de Python , Python Software Foundation , consultado el 24 de febrero de 2021printf
  28. "Printf() integrado de SQLite" . sqlite.org . Consultado el 24 de noviembre de 2025 .
  • Referencia de C++ parastd::fprintf
  • Referencia rápida de las especificaciones del formato printf de gcc
  • printf: salida formateada de impresión Referencia de interfaces del sistema, Especificación única de UNIX , Versión 5 de The Open Group   
  • La Formatterespecificación en Java 1.5
  • GNU Bash printf(1)integrado