cadena de formato scanf - scanf format string

Una cadena de formato scanf ( scan f ormatted) es un parámetro de control que se utiliza en varias funciones para especificar el diseño de una cadena de entrada . Las funciones pueden luego dividir la cadena y traducirse en valores de tipos de datos apropiados . Las funciones de escaneo de cadenas a menudo se proporcionan en bibliotecas estándar .

El término "scanf" proviene de la biblioteca C , que popularizó este tipo de función, pero tales funciones son anteriores a C, y se utilizan otros nombres, como readf en ALGOL 68 . Las cadenas de formato scanf, que proporcionan una entrada formateada ( análisis sintáctico ), son complementarias a las cadenas de formato printf , que proporcionan una salida formateada ( plantillas ). Estos proporcionan una funcionalidad simple y un formato fijo en comparación con analizadores o motores de plantillas más sofisticados y flexibles, pero son suficientes para muchos propósitos.

Historia

Mike Lesk 's biblioteca de entrada / salida portátil , incluyendo scanf , se convirtió oficialmente en parte de Unix en la versión 7 .

Uso

La scanf función, que se encuentra en C , lee la entrada para números y otros tipos de datos de la entrada estándar (a menudo una interfaz de línea de comandos o un tipo similar de interfaz de usuario de texto ).

El siguiente código C lee un número variable de enteros decimales sin formato del flujo de entrada estándar e imprime cada uno de ellos en líneas separadas:

#include <stdio.h>

int main(void)
{
    int n;

    while (scanf("%d", &n) == 1)
        printf("%d\n", n);
    return 0;
}

Después de ser procesada por el programa anterior, una lista de números enteros espaciados irregularmente, como

456 123 789 456 12
456 1
      2378

aparecerá constantemente espaciado como:

456
123
789
456
12
456
1
2378

Para imprimir una palabra:

#include <stdio.h>

int main(void)
{
    char word[20];

    if (scanf("%19s", word) == 1)
        puts(word);
    return 0;
}

Independientemente del tipo de datos que el programador desee que lea el programa, los argumentos (como los &n anteriores) deben ser punteros que apunten a la memoria. De lo contrario, la función no funcionará correctamente porque intentará sobrescribir las secciones incorrectas de la memoria, en lugar de apuntar a la ubicación de la memoria de la variable para la que está intentando obtener la entrada.

En el último ejemplo, un operador de dirección de ( & ) no se usa para el argumento: como word es el nombre de una matriz de char , como tal es (en todos los contextos en los que se evalúa como una dirección) equivalente a un puntero a la primera elemento de la matriz. Si bien la expresión &word se evaluaría numéricamente con el mismo valor, semánticamente, tiene un significado completamente diferente ya que representa la dirección de toda la matriz en lugar de un elemento de ella. Este hecho debe tenerse en cuenta al asignar scanf salida a cadenas.

Como scanf está diseñado para leer solo desde la entrada estándar, muchos lenguajes de programación con interfaces , como PHP , tienen derivados como sscanf y fscanf pero no él scanf mismo.

Formato de especificaciones de cadena

Los marcadores de posición de formato en scanf son más o menos los mismos que en printf , su función inversa. Como en printf, la extensión POSIX n$ está definida.

Rara vez hay constantes (es decir, caracteres que no formatean marcadores de posición ) en una cadena de formato, principalmente porque un programa generalmente no está diseñado para leer datos conocidos, aunque los scanf acepta si se especifican explícitamente. La excepción es uno o más caracteres de espacio en blanco , que descarta todos los caracteres de espacio en blanco en la entrada.

Algunos de los marcadores de posición más utilizados son los siguientes:

  • %a  : Escanea un número de punto flotante en su notación hexadecimal.
  • %d  : Escanea un entero como un número decimal con signo .
  • %i  : Escanea un entero como un número con signo. Similar a %d , pero interpreta el número como hexadecimal cuando está precedido por 0x y octal cuando está precedido por 0 . Por ejemplo, la cadena 031 se leería como 31 usando %d y 25 usando %i . La bandera h en %hi indica la conversión a una short y hh la conversión a una char .
  • %u  : Busque decimal unsigned int (tenga en cuenta que en el estándar C99 el valor de entrada menos signo es opcional, por lo que si se lee un signo menos, no surgirán errores y el resultado será el complemento a dos de un número negativo, probablemente un valor muy grande. Consulte strtoul() .) De forma correspondiente, %hu busca un unsigned short y %hhu un unsigned char .
  • %f  : Escanea un número de punto flotante en notación normal ( punto fijo ).
  • %g , %G  : Escanea un número de punto flotante en notación normal o exponencial. %g usa letras minúsculas y %G usa mayúsculas.
  • %x , %X  : Escanea un entero como un número hexadecimal sin signo .
  • %o  : Escanea un entero como un número octal .
  • %s  : Escanea una cadena de caracteres . El escaneo termina en espacios en blanco . Un carácter nulo se almacena al final de la cadena, lo que significa que el búfer proporcionado debe ser al menos un carácter más largo que la longitud de entrada especificada.
  • %c  : Escanea un carácter (char). No se agrega ningún carácter nulo .
  • espacio en blanco : cualquier carácter de espacio en blanco activa un escaneo de cero o más caracteres de espacio en blanco . No es necesario que el número y el tipo de caracteres de espacio en blanco coincidan en ninguna dirección.
  • %lf  : Escanee como un número de coma flotante doble . Formato "flotante" con el especificador "largo".
  • %Lf  : Escanee como un número de coma flotante doble largo . "Float" formatea el especificador "long long".
  • %n  : No se espera nada. El número de caracteres consumidos hasta ahora desde la entrada se almacena a través del siguiente puntero, que debe ser un puntero a int. Esta no es una conversión y no aumenta el recuento devuelto por la función.


Lo anterior se puede usar en compuesto con modificadores numéricos y los modificadores l , L que representan "long" y "long long" entre el símbolo de porcentaje y la letra. También puede haber valores numéricos entre el símbolo de porcentaje y las letras, antes de los long modificadores, si los hay, que especifican el número de caracteres que se escanearán. Un asterisco opcional ( * ) justo después del símbolo de porcentaje indica que el dato leído por este especificador de formato no se almacenará en una variable. No se debe incluir ningún argumento detrás de la cadena de formato para esta variable eliminada.

El ff modificador en printf no está presente en scanf, causando diferencias entre los modos de entrada y salida. Los modificadores ll y hh no están presentes en el estándar C90, pero están presentes en el estándar C99.

Un ejemplo de una cadena de formato es

"%7d%s %c%lf"

La cadena de formato anterior escanea los primeros siete caracteres como un entero decimal, luego lee el resto como una cadena hasta que se encuentra un espacio, una nueva línea o una pestaña, luego consume espacios en blanco hasta que se encuentra el primer carácter que no es un espacio en blanco, luego consume ese carácter, y finalmente escanea los caracteres restantes como un doble . Por lo tanto, un programa sólido debe verificar si la scanf llamada se realizó correctamente y tomar las medidas adecuadas. Si la entrada no estaba en el formato correcto, los datos erróneos seguirán estando en el flujo de entrada y deben descartarse antes de poder leer la nueva entrada. Un método alternativo, que evita esto, es utilizar fgets y luego examinar la cadena leída. El último paso se puede realizar sscanf , por ejemplo.

En el caso de los muchos caracteres de tipo flotante a, e, f, g , muchas implementaciones optan por colapsar la mayoría en el mismo analizador. Microsoft MSVCRT lo hace con e, f, g , mientras que glibc lo hace con los cuatro.

Vulnerabilidades

scanf es vulnerable a los ataques de cadenas de formato . Se debe tener mucho cuidado para garantizar que la cadena de formato incluya limitaciones para los tamaños de cadena y matriz. En la mayoría de los casos, el tamaño de la cadena de entrada de un usuario es arbitrario y no se puede determinar antes de scanf que se ejecute la función. Esto significa que los usos de %s marcadores de posición sin especificadores de longitud son intrínsecamente inseguros y explotables para desbordamientos de búfer . Otro problema potencial es permitir cadenas de formato dinámico, por ejemplo cadenas de formato almacenadas en archivos de configuración u otros archivos controlados por el usuario. En este caso, la longitud de entrada permitida de los tamaños de cadena no se puede especificar a menos que la cadena de formato se verifique de antemano y se apliquen las limitaciones. Relacionado con esto hay marcadores de posición de formato adicionales o no coincidentes que no coinciden con la lista de vararg real . Estos marcadores de posición pueden extraerse parcialmente de la pila o contener punteros indeseables o incluso inseguros, según la implementación particular de varargs .

Ver también

Referencias

enlaces externos