c buffer stdio

¿Cuáles son las reglas del lavado automático del búfer stdout en C?



buffer stdio (5)

Consulte la página de setbuf(3) de setbuf(3) . Por defecto, stdout está configurado en modo de almacenamiento en línea.

printf() y sus variantes funcionan con salida en búfer y delegan para write() . Por lo tanto, este almacenamiento en búfer está controlado por la implementación de la biblioteca C de printf , con la configuración del búfer y el búfer ubicados en la estructura FILE .

También vale la pena señalar la diferencia entre la sección 3 y la sección 2 de las páginas de manual de Unix. La Sección 2 está compuesta por llamadas a funciones que se comunican directamente con el sistema operativo y hacen cosas que de otro modo sería imposible hacer desde un programa de usuario puro. La Sección 3 está compuesta por llamadas a funciones que un usuario podría reproducir por sí mismo, que a menudo delegan a las llamadas a la sección 2. Las funciones de la Sección 2 contienen la "magia" de bajo nivel que permite a los programas C interactuar con el mundo exterior y realizar E / S. Las funciones de la sección 3 pueden proporcionar una interfaz más conveniente para las funciones de la sección 2.

printf , scanf , getchar , fputs y otras funciones FILE * funciones de la sección 3 que delegan a write() y read() , que son funciones de la sección 2. read() y write() no almacenan el búfer. printf() interactúa con el búfer en la estructura FILE , y ocasionalmente decide enviar el contenido de ese búfer a través de write() .

Tengo curiosidad por saber qué condiciones se deben cumplir para vaciar el búfer stdout automáticamente.

En primer lugar, estaba confundido de que este pseudocódigo no imprime resultados en cada iteración:

while (1) { printf("Any text"); sleep(1); }

Pero si agrego un carácter de nueva línea, lo hará.

Después de algunos experimentos, descubrí que en mi máquina el búfer stdout se vacía:

  1. Cuando pongo a stdout 1025 caracteres o más;
  2. Cuando leo stdin;
  3. Cuando pongo carácter de nueva línea en stdout;

La primera condición es totalmente clara: cuando el búfer está lleno, debe vaciarse. El segundo también es razonable. Pero, ¿por qué el personaje de nueva línea causa enrojecimiento? ¿Cuáles son las otras condiciones implícitas para esto?


Existen muchas circunstancias en las que la salida almacenada en un flujo se vacía automáticamente:

  1. Cuando intentas hacer una salida y el búfer de salida está lleno.
  2. Cuando la corriente está cerrada.
  3. Cuando el programa termina llamando a exit.
  4. Cuando se escribe una nueva línea, si la secuencia está almacenada en línea.
  5. Cada vez que una operación de entrada en cualquier flujo lee datos de su archivo.

stdout es un buffer de línea por defecto.

Si desea vaciar la salida almacenada en otro momento, puede llamar a fflush.


Las reglas del búfer stdout de lavado automático están definidas por la implementación (ID). Es ID cuando la secuencia no tiene búfer , está completamente en búfer o está en línea .

Cuando una secuencia no tiene búfer , los caracteres deben aparecer desde el origen o en el destino lo antes posible. De lo contrario, los caracteres pueden acumularse y transmitirse hacia o desde el entorno host como un bloque.

Cuando una secuencia está completamente almacenada en búfer , los caracteres están destinados a ser transmitidos hacia o desde el entorno host como un bloque cuando se llena un búfer.

Cuando una secuencia tiene un buffer de línea , los caracteres están destinados a ser transmitidos hacia o desde el entorno host como un bloque cuando se encuentra un carácter de nueva línea. Además, los caracteres están destinados a ser transmitidos como un bloque al entorno del host cuando se llena un búfer, cuando se solicita la entrada en un flujo sin búfer, o cuando se solicita la entrada en un flujo con búfer de línea que requiere la transmisión de caracteres desde el entorno del host .

El soporte para estas características está definido por la implementación , ... C11dr §7.21.3 3

Tengo curiosidad por saber qué condiciones se deben cumplir para vaciar el búfer stdout automáticamente.

Si el código quiere asegurar que la salida esté vacía, use fflush() . Otras condiciones que pueden vaciar automáticamente la secuencia son la implementación definida.


Estándar en línea C2011

7.21.3 Archivos
...
3 Cuando una secuencia no tiene búfer , los caracteres deben aparecer desde la fuente o en el destino lo antes posible. De lo contrario, los caracteres pueden acumularse y transmitirse hacia o desde el entorno host como un bloque. Cuando una secuencia está completamente almacenada en búfer , los caracteres están destinados a ser transmitidos hacia o desde el entorno host como un bloque cuando se llena un búfer. Cuando una secuencia tiene un buffer de línea , los caracteres están destinados a ser transmitidos hacia o desde el entorno host como un bloque cuando se encuentra un carácter de nueva línea. Además, los caracteres están destinados a ser transmitidos como un bloque al entorno del host cuando se llena un búfer, cuando se solicita la entrada en un flujo sin búfer, o cuando se solicita la entrada en un flujo con búfer de línea que requiere la transmisión de caracteres desde el entorno del host . El soporte para estas características está definido por la implementación y puede verse afectado a través de las funciones setbuf y setvbuf .
...
7 Al inicio del programa, tres flujos de texto están predefinidos y no necesitan abrirse explícitamente: entrada estándar (para leer la entrada convencional), salida estándar (para escribir la salida convencional) y error estándar (para escribir la salida de diagnóstico). Como se abrió inicialmente, el flujo de error estándar no está completamente protegido; las secuencias de entrada y salida estándar están totalmente almacenadas si solo se puede determinar que la secuencia no se refiere a un dispositivo interactivo.

Por lo tanto, una secuencia de línea con búfer se vaciará en una nueva línea. En la mayoría de los sistemas con los que tengo experiencia, stdout se almacena en línea en una sesión interactiva.


  • Un flujo de salida que está protegido con una línea se vaciará siempre que se envíe una nueva línea.

  • Una implementación puede (pero no se requiere) vaciar todos los flujos de salida con buffer de línea siempre que se intente una lectura desde cualquier flujo de entrada con buffer de línea.

  • Las implementaciones no pueden hacer que las transmisiones estén completamente protegidas por defecto a menos que se pueda determinar que no están asociadas con un "dispositivo interactivo". Por lo tanto, cuando stdin / stdout son terminales, no se pueden almacenar completamente en búfer, solo en línea (o sin búfer).

Si solo necesita un enjuague cuando la salida es a un terminal, es suficiente suponer que escribir una nueva línea da como resultado un enjuague. De lo contrario, debe llamar explícitamente a fflush donde sea necesario.