¿Por qué printf no se vacía después de la llamada a menos que haya una nueva línea en la cadena de formato?

7 minutos de lectura

avatar de usuario
Loco Chenz

Por que printf no vaciar después de la llamada a menos que haya una nueva línea en la cadena de formato? ¿Es este comportamiento POSIX? ¿Cómo podría tener printf enjuague inmediatamente cada vez?

  • investigaste si esto pasa con cualquier archivo o solo con terminales? eso parecería ser una característica inteligente de la terminal para no generar una línea incompleta desde un programa en segundo plano, aunque espero que no se aplique a la programa de primer plano.

    – PypeBros

    12 de noviembre de 2009 a las 16:50

  • Bajo Cygwin bash, veo este mismo mal comportamiento incluso si es una nueva línea es en la cadena de formato. Este problema es nuevo en Windows 7; el mismo código fuente funcionó bien en Windows XP. MS cmd.exe se vacía como se esperaba. La solución setvbuf(stdout, (char*)NULL, _IONBF, 0) soluciona el problema, pero seguramente no debería haber sido necesario. Estoy usando MSVC++ 2008 Express. ~~~

    – Steve Lanzadores

    8 de enero de 2013 a las 14:10

  • Para aclarar el título de la pregunta: printf(..) no hace ningún rubor en sí mismo, es el almacenamiento en búfer de stdout que puede vaciarse al ver una nueva línea (si tiene un búfer de línea). Reaccionaría de la misma manera a putchar('\n');asi que printf(..) no es especial en este sentido. Esto contrasta con cout << endl;la documentación de la cual menciona prominentemente el enrojecimiento. Él documentación de printf no menciona enrojecimiento en absoluto.

    –Evgeni Sergeev

    5 de abril de 2016 a las 14:02


  • escribir (/ vaciar) es potencialmente una operación costosa, probablemente esté almacenada en búfer por razones de rendimiento.

    – hanshenrik

    17 de agosto de 2017 a las 23:31


  • @EvgeniSergeev: ¿Existe un consenso de que la pregunta ha diagnosticado incorrectamente el problema y que el enrojecimiento ocurre cuando hay una nueva línea en el producción? (poner uno en la cadena de formato es una forma, pero no la única, de obtener uno en la salida).

    – Ben Voigt

    1 mayo 2020 a las 17:54


avatar de usuario
Aarón

Para descargar inmediatamente la llamada fflush(stdout) o fflush(NULL) (NULL significa vaciar todo).

  • Tenga en cuenta fflush(NULL); suele ser una muy mala idea. Matará el rendimiento si tiene muchos archivos abiertos, especialmente en un entorno de subprocesos múltiples donde luchará con todo por los bloqueos.

    – R.. GitHub DEJA DE AYUDAR A ICE

    9 de junio de 2011 a las 13:57

  • Acabo de encontrarme con un escenario en el que incluso hay un ‘\n’, printf() no se vacía. Se solucionó agregando un fflush (stdout), como mencionaste aquí. Pero me pregunto la razón por la que ‘\n’ no pudo vaciar el búfer en printf().

    – Qiang Xu

    28/04/2012 a las 19:45

  • @QiangXu, la salida estándar tiene un búfer de línea solo en el caso de que se pueda determinar definitivamente que se refiere a un dispositivo interactivo. Entonces, por ejemplo, si redirige la salida con myprog >/tmp/tmpfile, que tiene un búfer completo en lugar de un búfer de línea. De memoria, la determinación de si su salida estándar es interactiva se deja a la implementación.

    – pax diablo

    29 de abril de 2012 a las 0:20


  • además, en Windows llamar a setvbuf(…., _IOLBF) no funcionará ya que _IOLBF es lo mismo que _IOFBF allí: msdn.microsoft.com/en-us/library/86cebhfs.aspx

    –Piotr Lopusiewicz

    5 de febrero de 2015 a las 10:02

stdout está almacenado en el búfer, por lo que solo se generará después de que se imprima una nueva línea.

Para obtener resultados inmediatos, ya sea:

  1. Imprimir en estándar.
  2. Hacer stdout sin búfer.

  • O fflush(stdout).

    – RastaJedi

    22 de febrero de 2016 a las 22:47

  • “así que solo se generará después de que se imprima una nueva línea”. No solo esto, sino al menos otros 4 casos. búfer lleno, escribir en stderr (esta respuesta menciona más adelante), fflush(stdout), fflush(NULL).

    – chux – Reincorporar a Monica

    22 de diciembre de 2017 a las 10:20


  • “stdout is buffered” no es cierto, como se indica en el punto 2. De forma predeterminada, stdout se almacena en bloque cuando es un archivo normal y en línea cuando es un tty. Tal vez simplemente agregue “por defecto” a la frase “stdout is buffered”.

    – William Pursell

    14 de diciembre de 2021 a las 15:14

avatar de usuario
hospitalidad sureña

Probablemente sea así debido a la eficiencia y porque si tiene varios programas que escriben en un solo TTY, de esta manera no obtiene caracteres entrelazados en una línea. Entonces, si los programas A y B están generando, generalmente obtendrá:

program A output
program B output
program B output
program A output
program B output

Esto apesta, pero es mejor que

proprogrgraam m AB  ououtputputt
prproogrgram amB A  ououtputtput
program B output

Tenga en cuenta que ni siquiera se garantiza que se vacíe en una nueva línea, por lo que debe vaciar explícitamente si el vaciado es importante para usted.

  • O fflush(stdout).

    – RastaJedi

    22 de febrero de 2016 a las 22:47

  • “así que solo se generará después de que se imprima una nueva línea”. No solo esto, sino al menos otros 4 casos. búfer lleno, escribir en stderr (esta respuesta menciona más adelante), fflush(stdout), fflush(NULL).

    – chux – Reincorporar a Monica

    22 de diciembre de 2017 a las 10:20


  • “stdout is buffered” no es cierto, como se indica en el punto 2. De forma predeterminada, stdout se almacena en bloque cuando es un archivo normal y en línea cuando es un tty. Tal vez simplemente agregue “por defecto” a la frase “stdout is buffered”.

    – William Pursell

    14 de diciembre de 2021 a las 15:14

avatar de usuario
o_O

Generalmente hay 2 niveles de almacenamiento en búfer:

1. Caché del búfer del núcleo (hace que la lectura/escritura sea más rápida)

2. Almacenamiento en búfer en la biblioteca de E/S (reduce el número de llamadas al sistema)

Tomemos ejemplo de fprintf and write().

Cuando usted llama fprintf(), no se escribe directamente en el archivo. Primero va al búfer stdio en la memoria del programa. Desde allí, se escribe en la memoria caché del búfer del kernel mediante una llamada al sistema de escritura. Entonces, una forma de omitir el búfer de E/S es directamente usando write(). Otras formas son usando setbuff(stream,NULL). Esto establece el modo de almacenamiento en búfer en ningún almacenamiento en búfer y los datos se escriben directamente en el búfer del núcleo. Para hacer que los datos se transfieran a la fuerza al búfer del kernel, podemos usar “\n”, que en el caso del modo de búfer predeterminado de ‘búfer de línea’, vaciará el búfer de E/S. O podemos usar fflush(FILE *stream).

Ahora estamos en el búfer del núcleo. Kernel (/OS) quiere minimizar el tiempo de acceso al disco y, por lo tanto, solo lee/escribe bloques de disco. Así que cuando un read() se emite, que es una llamada al sistema y se puede invocar directamente o a través de fscanf(), el núcleo lee el bloque de disco del disco y lo almacena en un búfer. Después de eso, los datos se copian desde aquí al espacio del usuario.

Del mismo modo que fprintf() El kernel escribe en el disco los datos recibidos del búfer de E/S. Esto hace que read() write() sea más rápido.

Ahora, para obligar al kernel a iniciar un write(), después de lo cual la transferencia de datos es controlada por controladores de hardware, también hay algunas formas. Nosotros podemos usar O_SYNC o indicadores similares durante las llamadas de escritura. O podríamos usar otras funciones como fsync(),fdatasync(),sync() para hacer que el núcleo inicie escrituras tan pronto como los datos estén disponibles en el búfer del núcleo.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad