stringtranslate.com

imprimirf

Un ejemplo de la función printf

La familia de funciones printf en el lenguaje de programación C es un conjunto de funciones que toman una cadena de formato como entrada entre una lista de tamaño variable de otros valores y producen como salida una cadena que corresponde al especificador de formato y a los valores de entrada dados. La cadena está escrita en un lenguaje de plantilla simple : los caracteres generalmente se copian literalmente en la salida de la función, pero los especificadores de formato , que comienzan con un %carácter, indican la ubicación y el método para traducir un dato (como un número) a caracteres. El diseño se ha copiado para exponer una funcionalidad similar en otros lenguajes de programación .

"printf" es el nombre de una de las principales funciones de salida de C y significa " imprimir formateado". Las cadenas en formato printf son complementarias a las cadenas en formato scanf , que proporcionan entrada formateada ( lexing también conocido como parsing ). En ambos casos, estos proporcionan una funcionalidad simple y un formato fijo en comparación con motores de plantillas o lexers/analizadores más sofisticados y flexibles, pero son suficientes para muchos propósitos.

Muchos lenguajes distintos de C copian la sintaxis de cadena en formato printf de manera cercana o exacta en sus propias funciones de E/S.

Las discrepancias entre los especificadores de formato y el tipo de datos pueden provocar fallos y otras vulnerabilidades. La cadena de formato en sí suele ser una cadena literal , lo que permite el 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 el formateo dinámico pero también una vulnerabilidad de seguridad conocida como exploit de cadena de formato no controlado .

Historia

Los primeros lenguajes de programación, como Fortran, utilizaban declaraciones especiales con una sintaxis completamente diferente a la de otros cálculos para crear descripciones de formato. En este ejemplo, el formato se especifica en la línea 601 y el comando WRITE hace referencia a él por número de línea:

  ESCRIBIR CINTA DE SALIDA 6 , 601 , IA , IB , IC , ÁREA 601 FORMATO ( 4 H A = , I5 , 5 H B = , I5 , 5 H C = , I5 , & 8 H ÁREA = , F10 . 2 , 13 H UNIDADES CUADRADA )                      

ALGOL 68 tenía una API más similar a funciones , pero aún usaba una sintaxis especial (los $delimitadores rodean la sintaxis de formato especial):

printf (( $ "Color " g ", numero1 " 6 d , ", numero2 " 4 zd , ", hexadecimal " 16 r2d , ", float " - d .2 d , ", valor sin signo" -3 d "." l$ , "rojo" , 123456 , 89 , BIN 255 , 3,14 , 250 ));       

Pero el uso de llamadas a funciones y tipos de datos normales simplifica el lenguaje y el compilador, y permite que la implementación de la entrada/salida se escriba en el mismo lenguaje. Estas ventajas superan las desventajas (como la falta total de seguridad de tipos en muchos casos) y en la mayoría de los lenguajes más nuevos, la E/S no forma parte de la sintaxis.

C printftiene su origen en la función BCPLwritef (1966). En comparación con Cy printf, es una secuencia de escape del lenguaje*N BCPL que representa un carácter de nueva línea (para el cual C usa la secuencia de escape ) y el orden del ancho y tipo de campo de la especificación de formato se invierte en : [1]\nwritef

WRITEF("EL PROBLEMA DE %I2-QUEENS TIENE %I5 SOLUCIONES*N", NUMQUEENS, COUNT)

Probablemente la primera copia de la sintaxis fuera del lenguaje C fue el printfcomando shell de Unix, que apareció por primera vez en la Versión 4 , como parte de la adaptación a C. [2]

Especificación del marcador de posición de formato

El formateo se realiza mediante marcadores de posición dentro de la cadena de formato. Por ejemplo, si un programa quisiera imprimir la edad de una persona, podría presentar el resultado anteponiendo "Tu edad es " y usando el carácter especificador decimal con signo dpara indicar que queremos que el número entero de la edad se muestre inmediatamente. después de ese mensaje, podemos usar la cadena de formato:

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

Sintaxis

La sintaxis de un marcador de posición de formato es

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

Campo de parámetros

Esta es una extensión POSIX y no en C99 . El campo Parámetro se puede omitir o puede ser:

Esta característica se utiliza principalmente en la localización, donde el orden de aparición de los parámetros varía debido a la convención que depende del idioma.

En Microsoft Windows que no es POSIX, la compatibilidad con esta característica se coloca en una función printf_p separada.

Campo de banderas

El campo Banderas puede ser cero o más (en cualquier orden) de:

Campo ancho

El campo Ancho especifica una cantidad mínima de caracteres para generar y generalmente se usa para rellenar campos de ancho fijo en la salida tabulada, donde de otro modo los campos serían más pequeños, aunque no provoca el truncamiento de campos de gran tamaño.

Se puede omitir el campo ancho, o un valor entero numérico, o un valor dinámico cuando se pasa como otro argumento cuando se indica con un asterisco *. [3] Por ejemplo, printf("%*d", 5, 10)se imprimirá 10con un ancho total de 5 caracteres.

Aunque no forma parte del campo de ancho, un cero a la izquierda se interpreta como el indicador de relleno con 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.

Campo de precisión

El campo Precisión normalmente especifica un límite máximo en la salida, dependiendo del tipo de formato particular. Para tipos numéricos de punto flotante, especifica el número de dígitos a la derecha del punto decimal que se debe redondear la salida. Para el tipo de cadena, limita la cantidad de caracteres que deben generarse, después de lo cual la cadena se trunca.

Se puede omitir el campo de precisión, o un valor entero numérico, o un valor dinámico cuando se pasa como otro argumento cuando se indica con un asterisco *. Por ejemplo, printf("%.*s", 3, "abcdef")resultará en abcser impreso.

Campo de longitud

El campo Longitud se puede omitir o ser cualquiera de:

Además, surgieron varias opciones de longitud específicas de la plataforma antes del uso generalizado de las extensiones ISO C99:

ISO C99 incluye el inttypes.harchivo de encabezado que incluye una serie de macros para usar en printfcodificación independiente de la plataforma. Deben estar fuera de comillas dobles, por ejemploprintf("%" PRId64 "\n", t);

Las macros de ejemplo incluyen:

Tipo de campo

El campo Tipo puede ser cualquiera de:

Marcadores de posición de formato personalizado

Hay algunas implementaciones de printffunciones similares que permiten extensiones al minilenguaje basado en caracteres de escape , lo que permite al programador tener una función de formato específica para tipos no integrados. Uno de los más conocidos es el (ahora obsoleto) Register_printf_function() de glibc . Sin embargo, rara vez se utiliza debido al hecho de que entra en conflicto con la verificación de cadenas de formato estático. Otro son los formateadores personalizados Vstr, que permiten agregar nombres de formato de varios caracteres.

Algunas aplicaciones (como el servidor HTTP Apache ) incluyen su propia printffunción similar e incorporan extensiones. Sin embargo, todos estos tienden a tener los mismos problemas que register_printf_function()él.

La función del kernel de Linux printk admite varias formas de mostrar las estructuras del kernel utilizando la %pespecificación genérica, agregando caracteres de formato adicionales. [8] Por ejemplo, %pI4imprime una dirección IPv4 en formato decimal con puntos. Esto permite la verificación de cadenas de formato estático (de la %pporción) a expensas de la compatibilidad total con printf normal.

La mayoría de los lenguajes que tienen una printffunción similar solucionan la falta de esta característica simplemente usando el %sformato y convirtiendo el objeto en una representación de cadena.

Vulnerabilidades

Especificaciones de conversión no válidas

Si se proporcionan muy pocos argumentos de función para proporcionar valores para todas las especificaciones de conversión en la cadena de plantilla, o si los argumentos no son del tipo correcto, los resultados no estarán definidos y el programa puede fallar. Las implementaciones son inconsistentes en cuanto a si los errores de sintaxis en la cadena consumen un argumento y qué tipo de argumento consumen. Se ignoran los argumentos excesivos. En varios casos, el comportamiento indefinido ha dado lugar a vulnerabilidades de seguridad de " ataque de cadena de formato " . En la mayoría de las convenciones de llamadas de C o C++, los argumentos se pueden pasar en la pila, lo que significa que, en el caso de muy pocos argumentos, printf leerá más allá del final del marco de pila actual, permitiendo así que el atacante lea la pila.

Algunos compiladores, como GNU Compiler Collection , verificarán estáticamente las cadenas de formato de funciones similares a printf y advertirán sobre problemas (cuando se usan las banderas -Wallo -Wformat). GCC también advertirá sobre funciones de estilo printf definidas por el usuario si __attribute__se aplica el "formato" no estándar a la función.

Ancho de campo versus delimitadores explícitos en salida tabular

Usar solo anchos de campo para la tabulación, como ocurre con un formato como el %8d%8d%8dde tres números enteros en tres columnas de 8 caracteres, no garantizará que se mantenga la separación de campos si aparecen números grandes en los datos:

1234567 1234567 1234567123 123 123 123 12345678123 

La pérdida de separación de campos puede provocar fácilmente resultados corruptos. En los sistemas que fomentan el uso de programas como bloques de construcción en scripts, estos datos corruptos a menudo pueden reenviarse y corromper el procesamiento posterior, independientemente de si el programador original esperaba que el resultado solo fuera leído por ojos humanos. Estos problemas se pueden eliminar incluyendo delimitadores explícitos, incluso espacios, en todos los formatos de salida tabulares. Simplemente cambiar el peligroso ejemplo anterior para %7d %7d %7dabordar esto, formatear de manera idéntica hasta que los números se hagan más grandes, pero luego evitar explícitamente que se fusionen en la salida debido a los espacios explícitamente incluidos:

1234567 1234567 1234567123 123 123 123 12345678 123 

Se aplican estrategias similares a los datos de cadenas.

Escritura de memoria

Aunque es una función de salida en la superficie, printfpermite escribir en una ubicación de memoria especificada por un argumento a través de %n. Esta funcionalidad se utiliza ocasionalmente como parte de ataques de cadenas de formato más elaborados. [9]

La %nfuncionalidad también hace que Turing sea completoprintf accidentalmente incluso con un conjunto de argumentos bien formado. Un juego de tres en raya escrito en formato cadena es el ganador del 27º IOCCC . [10]

Lenguajes de programación con printf

No se incluyen en esta lista los lenguajes que usan cadenas de formato que se desvían del estilo de este artículo (como AMPL y Elixir ), los lenguajes que heredan su implementación de la JVM u otro entorno (como Clojure y Scala ) y los lenguajes que no lo hacen. no tiene una implementación printf nativa estándar pero tiene bibliotecas externas que emulan el comportamiento de printf (como JavaScript ).

Ver también

Referencias

  1. ^ "BCPL". cl.cam.ac.uk.​ Consultado el 19 de marzo de 2018 .
  2. ^ McIlroy, Doctor en Medicina (1987). Un lector de Research Unix: extractos comentados del Manual del programador, 1971-1986 (PDF) (Informe técnico). CSTR. Laboratorios Bell. 139.
  3. ^ "imprimirf". cplusplus.com . Consultado el 10 de junio de 2020 .
  4. ^ ISO / IEC (1999). ISO/IEC 9899:1999(E): Lenguajes de programación – C §7.19.6.1 párrafo 7 .
  5. ^ ""Manual de referencia de la biblioteca GNU C", "12.12.3 Tabla de conversiones de salida"". Gnu.org . Consultado el 17 de marzo de 2014 .
  6. ^ "printf" ( %a agregado en C99)
  7. ^ "Formato de salida de impresión numérica". Los tutoriales de Java . oráculo inc . Consultado el 19 de marzo de 2018 .
  8. ^ "Documentación del kernel de Linux/printk-formats.txt". Git.kernel.org. Archivado desde el original el 29 de abril de 2015 . Consultado el 17 de marzo de 2014 .
  9. ^ https://www.exploit-db.com/docs/english/28476-linux-format-string-exploitation.pdf [ URL básica PDF ]
  10. ^ "Lo mejor del espectáculo: abuso de libc". Ioccc.org . Consultado el 5 de mayo de 2022 .
  11. ^ ""Las especificaciones básicas de Open Group, edición 7, edición de 2018", "POSIX awk", "Declaraciones de salida"". pubs.opengroup.org . Consultado el 29 de mayo de 2022 .
  12. ^ "Biblioteca estándar de Printf". El manual de idiomas de Julia . Consultado el 22 de febrero de 2021 .
  13. ^ "Tipos integrados: formato de cadena estilo printf", The Python Standard Library , Python Software Foundation , consultado el 24 de febrero de 2021

enlaces externos