c gcc glibc scanf

diferencia entre% ms y% s scanf



gcc glibc (1)

El estándar C no define dicho carácter opcional en los formatos scanf() .

GNU lib C, define un indicador opcional de esta manera (desde la página del manual para scanf ):

Un personaje opcional. Esto se usa con las conversiones de cadenas y alivia a la persona que llama de la necesidad de asignar un búfer correspondiente para contener la entrada: en su lugar, scanf() asigna un búfer de tamaño suficiente y asigna la dirección de este búfer al argumento del puntero correspondiente, que debe ser un puntero a una variable char * (esta variable no necesita inicializarse antes de la llamada).

La persona que llama posteriormente debe free este búfer cuando ya no sea necesario. Esta es una extensión de GNU; C99 emplea el carácter a como un especificador de conversión (y también se puede usar como tal en la implementación de GNU).

La sección de NOTAS de la página del manual dice:

El modificador a no está disponible si el programa se compila con gcc -std=c99 o gcc -D_ISOC99_SOURCE (a menos que también se especifique _GNU_SOURCE ), en cuyo caso el a se interpreta como un especificador para números de punto flotante (ver arriba).

Desde la versión 2.7, glibc también proporciona el modificador m para el mismo propósito que el modificador a. El modificador m tiene las siguientes ventajas:

  • También se puede aplicar a los especificadores de conversión %c (p. Ej., %3mc ).

  • Evita la ambigüedad con respecto al %a especificador de conversión de punto flotante (y no se ve afectado por gcc -std=c99 etc.)

  • Se especifica en la próxima revisión del estándar POSIX.1.

La página del manual de Linux en línea en http://linux.die.net/man/3/scanf solo documenta esta opción como:

Un carácter opcional ''m''. Esto se usa con las conversiones de cadenas ( %s , %c , %[ ) y alivia a la persona que llama de la necesidad de asignar un búfer correspondiente para contener la entrada: en su lugar, scanf() asigna un búfer de tamaño suficiente y asigna la dirección de este búfer al argumento del puntero correspondiente, que debería ser un puntero a una variable char * (esta variable no necesita inicializarse antes de la llamada). La persona que llama posteriormente debe free(3) este búfer cuando ya no sea necesario.

El estándar Posix documenta esta extensión en su edición POSIX.1-2008 (ver http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html ):

Los especificadores de conversión %c , %s y %[ aceptarán un carácter opcional de asignación-asignación m , que hará que se asigne un búfer de memoria para mantener la cadena convertida, incluido un carácter nulo de terminación. En tal caso, el argumento correspondiente al especificador de conversión debe ser una referencia a una variable de puntero que recibirá un puntero al búfer asignado. El sistema asignará un búfer como si se hubiera llamado malloc() . La aplicación será responsable de liberar la memoria después del uso. Si no hay suficiente memoria para asignar un búfer, la función establecerá errno en [ ENOMEM ] y se producirá un error de conversión. Si la función devuelve EOF , cualquier memoria asignada con éxito para los parámetros que utilizan el carácter de asignación-asignación m por esta llamada se liberará antes de que la función regrese.

Usando esta extensión, podrías escribir:

char *p; scanf("%ms", &p);

Causando scanf para analizar una palabra de la entrada estándar y asignar suficiente memoria para almacenar sus caracteres más un ''/0'' termina. Un puntero a la matriz asignada se almacenaría en p y scanf() devolvería 1 , a menos que no se puedan leer caracteres que no sean espacios en blanco desde stdin .

Es completamente posible que otros sistemas usen m para una semántica similar o para algo completamente diferente. Las extensiones no estándar no son portátiles y deben usarse con mucho cuidado, documentadas como tales, en circunstancias en las que un enfoque estándar es engorroso poco práctico o totalmente imposible.

Tenga en cuenta que analizar una palabra de tamaño arbitrario es realmente imposible con la versión estándar de scanf() :

Puede analizar una palabra con un tamaño máximo y debe especificar el número máximo de caracteres para almacenar antes del ''/0'' :

char buffer[20]; scanf("%19s", buffer);

Pero esto no le indica cuántos caracteres más están disponibles para analizar en la entrada estándar. En cualquier caso, no pasar el número máximo de caracteres puede invocar un comportamiento indefinido si la entrada es lo suficientemente larga, y un atacante puede incluso utilizar una entrada especialmente diseñada para comprometer su programa:

char buffer[20]; scanf("%s", buffer); // potential undefined behavior, // that could be exploited by an attacker.

Al leer el manual de scanf me encuentro con esta línea:

Un carácter opcional ''m''. Esto se usa con las conversiones de cadenas (% s,% c,% [),

¿Alguien puede explicarlo con un ejemplo simple que indique la diferencia y la necesidad de tal opción en algunos casos?