Saltar al contenido

Usando fflush (stdin)

Nuestro equipo especializado pasados muchos días de trabajo y de juntar de información, obtuvimos la solución, nuestro deseo es que te sea de utilidad en tu proyecto.

Solución:

Simple: este es un comportamiento indefinido, ya que fflush está destinado a ser llamado en un flujo de salida. Este es un extracto del estándar C:

int fflush (ARCHIVO * ostream);

ostream apunta a un flujo de salida o un flujo de actualización en el que no se ingresó la operación más reciente, la función fflush hace que cualquier dato no escrito para ese flujo se entregue al entorno host para que se escriba en el archivo; de lo contrario, el comportamiento no está definido.

Así que no se trata de “qué tan malo” es esto. fflush(stdin) es claramente mal, y tu no debo usarlo, nunca.

Convertir comentarios en una respuesta y ampliarlos ya que el problema reaparece periódicamente.

Licencia estándar C y POSIX fflush(stdin) como comportamiento indefinido

Los estándares POSIX, C y C ++ para fflush() declaran explícitamente que el comportamiento no está definido, pero ninguno de ellos impide que un sistema lo defina.

ISO / IEC 9899: 2011 – el estándar C11 – dice:

§7.21.5.2 La función de descarga

¶2 Si stream apunta a un flujo de salida o un flujo de actualización en el que no se ingresó la operación más reciente, el fflush La función hace que cualquier dato no escrito para esa secuencia que se entregue al entorno de host se escriba en el archivo; de lo contrario, el comportamiento no está definido.

POSIX en su mayoría difiere del estándar C, pero marca este texto como una extensión C.

[CX] Para una secuencia abierta para lectura, si el archivo aún no está en EOF, y el archivo es capaz de buscar, el desplazamiento del archivo de la descripción del archivo abierto subyacente se establecerá en la posición del archivo de la secuencia y los caracteres retrocederán. en el arroyo por ungetc() o ungetwc() que no se hayan leído posteriormente de la secuencia se descartarán (sin cambiar más el desplazamiento del archivo).

Tenga en cuenta que los terminales no son capaces de buscar; tampoco lo son las tuberías ni los enchufes.

Microsoft define el comportamiento de fflush(stdin)

Microsoft y el tiempo de ejecución de Visual Studio definen la definición del comportamiento de fflush() en un flujo de entrada.

Si la transmisión está abierta para entrada, fflush borra el contenido del búfer.

MM notas:

Cygwin es un ejemplo de una plataforma bastante común en la que fflush(stdin) no borra la entrada.

Es por eso que esta versión de respuesta de mi comentario señala ‘Microsoft y el tiempo de ejecución de Visual Studio’: si usa una biblioteca en tiempo de ejecución que no es de Microsoft C, el comportamiento que ve depende de esa biblioteca.

La documentación y la práctica de Linux parecen contradecirse entre sí

Sorprendentemente, Linux documenta nominalmente el comportamiento de fflush(stdin) también, e incluso lo define de la misma manera (milagro de milagros).

Para flujos de entrada, fflush() descarta cualquier dato almacenado en búfer que se haya obtenido del archivo subyacente, pero que la aplicación no haya consumido.

Me quedo un poco perplejo y sorprendido por la documentación de Linux que dice que fflush(stdin) trabajará. A pesar de esa sugerencia, generalmente no funciona en Linux. Acabo de comprobar la documentación en Ubuntu 14.04 LTS; dice lo que se cita arriba, pero empíricamente, no funciona, al menos cuando el flujo de entrada es un dispositivo que no se puede buscar, como un terminal.

demo-fflush.c

#include 

int main(void)

    int c;
    if ((c = getchar()) != EOF)
    
        printf("Got %c; enter some new datan", c);
        fflush(stdin);
    
    if ((c = getchar()) != EOF)
        printf("Got %cn", c);

    return 0;

Salida de ejemplo

$ ./demo-fflush
Alliteration
Got A; enter some new data
Got l
$

Esta salida se obtuvo en Ubuntu 14.04 LTS y Mac OS X 10.11.2. A mi entender, contradice lo que dice el manual de Linux. Si el fflush(stdin) La operación funcionó, tendría que escribir una nueva línea de texto para obtener información para el segundo getchar() leer.

Dado lo que dice el estándar POSIX, tal vez se necesite una mejor demostración y la documentación de Linux debería aclararse.

demo-fflush2.c

#include 

int main(void)

    int c;
    if ((c = getchar()) != EOF)
    
        printf("Got %cn", c);
        ungetc('B', stdin);
        ungetc('Z', stdin);
        if ((c = getchar()) == EOF)
        
            fprintf(stderr, "Huh?!n");
            return 1;
        
        printf("Got %c after ungetc()n", c);
        fflush(stdin);
    
    if ((c = getchar()) != EOF)
        printf("Got %cn", c);

    return 0;

Salida de ejemplo

Tenga en cuenta que /etc/passwd es un archivo que se puede buscar. En Ubuntu, la primera línea se ve así:

root:x:0:0:root:/root:/bin/bash

En Mac OS X, las primeras 4 líneas se ven así:

##
# User Database
# 
# Note that this file is consulted directly only when the system is running

En otras palabras, hay comentarios en la parte superior de Mac OS X /etc/passwd expediente. Las líneas sin comentarios se ajustan al diseño normal, por lo que root la entrada es:

root:*:0:0:System Administrator:/var/root:/bin/sh

Ubuntu 14.04 LTS:

$ ./demo-fflush2 < /etc/passwd
Got r
Got Z after ungetc()
Got o
$ ./demo-fflush2
Allotrope
Got A
Got Z after ungetc()
Got B
$

Mac OS X 10.11.2:

$ ./demo-fflush2 < /etc/passwd
Got #
Got Z after ungetc()
Got B
$

El comportamiento de Mac OS X ignora (o al menos parece ignorar) la fflush(stdin) (por lo tanto, no sigue POSIX en este tema). El comportamiento de Linux corresponde al comportamiento POSIX documentado, pero la especificación POSIX es mucho más cuidadosa en lo que dice: especifica un archivo capaz de buscar, pero los terminales, por supuesto, no admiten la búsqueda. También es mucho menos útil que la especificación de Microsoft.

Resumen

Microsoft documenta el comportamiento de fflush(stdin). Aparentemente, funciona como se documenta en la plataforma Windows, utilizando el compilador nativo de Windows y las bibliotecas de soporte de tiempo de ejecución de C.

A pesar de la documentación que indica lo contrario, no funciona en Linux cuando la entrada estándar es una terminal, pero parece seguir la especificación POSIX, que está redactada con mucho más cuidado. Según el estándar C, el comportamiento de fflush(stdin) es indefinido. POSIX agrega el calificador 'a menos que se pueda buscar el archivo de entrada', que no es un terminal. El comportamiento no es el mismo que el de Microsoft.

En consecuencia, el código portátil no utiliza fflush(stdin). El código que está vinculado a la plataforma de Microsoft puede usarlo y funcionará, pero tenga cuidado con los problemas de portabilidad.

POSIX forma de descartar la entrada de terminal no leída de un descriptor de archivo

La forma estándar POSIX de descartar información no leída de un descriptor de archivo de terminal (a diferencia de un flujo de archivos como stdin) se ilustra en ¿Cómo puedo eliminar datos no leídos de una cola de entrada tty en un sistema Unix? Sin embargo, eso está funcionando por debajo del nivel de biblioteca de E / S estándar.

Según el estándar, fflush solo se puede usar con búferes de salida, y obviamente stdin no es uno. Sin embargo, algunas bibliotecas C estándar proporcionan el uso de fflush(stdin) como una extensión. En ese caso, puede usarlo, pero afectará la portabilidad, por lo que ya no podrá usar ninguna biblioteca C estándar compatible con los estándares en la tierra y esperar los mismos resultados.

valoraciones y reseñas

Agradecemos que desees añadir valor a nuestra información cooperando tu experiencia en las anotaciones.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *