Question Pourquoi printf ne se vide-t-il pas après l'appel, sauf si une nouvelle ligne est dans la chaîne de format?


Pourquoi printf pas vider après l'appel, sauf si un retour à la ligne est dans la chaîne de format? Est ce comportement POSIX? Comment pourrais-je avoir printf rincer immédiatement à chaque fois?


431
2017-11-11 16:22


origine


Réponses:


le stdout Le flux est tamponné, donc il n'affiche que ce qu'il y a dans le tampon après qu'il a atteint une nouvelle ligne (ou quand on lui a dit de le faire). Vous avez quelques options à imprimer immédiatement:

Imprimer sur stderr à la place en utilisant fprintf:

fprintf(stderr, "I will be printed immediately");

Vider la sortie stdout quand vous en avez besoin fflush:

printf("Buffered, will be flushed");
fflush(stdout); // Will now print everything in the stdout buffer

modifier: D'après le commentaire d'Andy Ross ci-dessous, vous pouvez également désactiver la mise en mémoire tampon sur stdout en utilisant setbuf:

setbuf(stdout, NULL);

555
2017-11-11 17:04



Non, ce n'est pas un comportement POSIX, c'est un comportement ISO (bien, ça est Comportement POSIX mais seulement dans la mesure où ils sont conformes à la norme ISO).

La sortie standard est mise en mémoire tampon si elle peut être détectée comme faisant référence à un périphérique interactif, sinon elle est entièrement mise en mémoire tampon. Donc, il y a des situations où printf ne videra pas, même si une nouvelle ligne est envoyée, par exemple:

myprog >myfile.txt

Cela a du sens pour l'efficacité puisque, si vous interagissez avec un utilisateur, ils veulent probablement voir chaque ligne. Si vous envoyez la sortie dans un fichier, il est fort probable qu'il n'y ait pas d'utilisateur à l'autre extrémité (bien que ce ne soit pas impossible, ils pourraient être en train de gérer le fichier). Maintenant, c'est à votre tour pourrait argumenter que l'utilisateur veut voir tous les caractères mais il y a deux problèmes avec cela.

Le premier est que ce n'est pas très efficace. La seconde est que le mandat initial de l’ANSI C consistait principalement à codifier existant comportement, plutôt que d'inventer Nouveau comportement, et ces décisions de conception ont été prises bien avant le lancement du processus par ANSI. Même ISO, de nos jours, fait très attention lors de la modification des règles existantes dans les normes.

Quant à savoir comment faire face à cela, si vous fflush (stdout) après chaque appel de sortie que vous voulez voir immédiatement, cela résoudra le problème.

Alternativement, vous pouvez utiliser setvbuf avant d'opérer stdout, pour le régler sur sans tampon et vous n'aurez pas à vous soucier de l'ajout de tous fflush lignes à votre code:

setvbuf (stdout, NULL, _IONBF, BUFSIZ);

Gardez à l'esprit que cela peut affecter un peu la performance si vous sont envoyer la sortie à un fichier. Gardez également à l’esprit que la prise en charge pour cela est définie par la mise en œuvre, non garantie par la norme.

Section ISO C99 7.19.3/3 est le bit pertinent:

Quand un flux est sans tampon, les caractères sont destinés à apparaître de la source ou de la destination dès que possible. Sinon, les caractères peuvent être accumulés et transmis vers ou depuis l'environnement hôte en tant que bloc.

Quand un flux est entièrement tamponnée, les caractères sont destinés à être transmis vers ou depuis l'environnement hôte en tant que bloc lorsqu'un tampon est rempli.

Quand un flux est ligne tamponnée, les caractères sont destinés à être transmis vers ou depuis l'environnement hôte en tant que bloc lorsqu'un caractère de nouvelle ligne est rencontré.

De plus, les caractères sont destinés à être transmis en tant que bloc à l'environnement hôte lorsqu'un tampon est rempli, lorsqu'une entrée est demandée sur un flux sans tampon ou lorsque l'entrée est demandée sur un flux en ligne qui nécessite la transmission de caractères de l'environnement hôte. .

La prise en charge de ces caractéristiques est définie par la mise en œuvre et peut être affectée via le setbuf et setvbuf les fonctions.


97
2017-11-17 03:52



C'est probablement comme ça parce que c'est efficace et parce que si vous avez plusieurs programmes qui écrivent sur un seul TTY, vous n'obtiendrez pas de caractères sur une ligne entrelacée. Donc, si les programmes A et B sortent, vous obtiendrez généralement:

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

Cela pue, mais c'est mieux que

proprogrgraam m AB  ououtputputt
prproogrgram amB A  ououtputtput
program B output

Notez qu'il n'est même pas garanti d'effectuer un vidage sur un retour à la ligne, vous devez donc vidanger explicitement si le rinçage est important pour vous.


22
2017-11-11 17:54



Pour rincer immédiatement l'appel fflush(stdout) ou fflush(NULL) (NULL signifie tout rincer).


18
2017-11-11 16:26



Remarque: Les bibliothèques d'exécution Microsoft ne prennent pas en charge la mise en mémoire tampon de ligne. printf("will print immediatelly to terminal"):

http://msdn.microsoft.com/en-us/library/86cebhfs.aspx


11
2017-10-26 20:47



stdout est mis en mémoire tampon, donc ne sera affiché qu'après l'impression d'une nouvelle ligne.

Pour obtenir une sortie immédiate, soit:

  1. Imprimer sur stderr.
  2. Faites en sorte que stdout ne soit pas tamponné.

10
2017-11-11 16:25



Par défaut, stdout est mis en mémoire tampon, stderr n'est pas mis en mémoire tampon et le fichier est complètement tamponné.


10
2017-07-29 02:02