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?
¿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?
Loco Chenz
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:
- Imprimir en estándar.
- 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
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
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.
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 destdout
que puede vaciarse al ver una nueva línea (si tiene un búfer de línea). Reaccionaría de la misma manera aputchar('\n');
asi queprintf(..)
no es especial en este sentido. Esto contrasta concout << 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