Pourquoi printf ne tire-t-il pas la chasse d'eau après l'appel à moins qu'une nouvelle ligne ne soit dans la chaîne de format?

pourquoi printf ne tire-t-il pas la chasse après l'appel à moins qu'une nouvelle ligne ne soit dans la chaîne de format? C'est un comportement POSIX? Comment pourrais-je avoir printf immédiatement tirer la chasse à chaque fois?

444
demandé sur K DawG 2009-11-11 19:22:39

9 réponses

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

Imprimer vers stderr à l'aide de fprintf :

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

Flush stdout chaque fois que vous en avez besoin à l'aide de fflush :

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

Edit : du commentaire D'Andy Ross ci-dessous, vous pouvez également désactiver tampon sur la sortie standard en utilisant setbuf :

setbuf(stdout, NULL);
573
répondu Rudd Zwolinski 2009-11-11 20:24:36

non, ce n'est pas un comportement POSIX, c'est un comportement ISO (Eh bien, c'est c'est comportement POSIX mais seulement dans la mesure où ils sont conformes à ISO).

La sortie Standard

est amortie en ligne si elle peut être détectée pour se référer à un périphérique interactif, sinon elle est complètement amortie. Il y a donc des situations où printf ne tire pas la chasse, même s'il obtient une nouvelle ligne à envoyer, comme:

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 à un fichier, il est très probable qu'il n'y ait pas d'utilisateur à l'autre extrémité (bien que cela ne soit pas impossible, ils pourraient suivre le fichier). Maintenant, vous pourrait argumenter que l'utilisateur veut voir chaque caractère, mais il ya deux problèmes avec cela.

la première, c'est que ce n'est pas très efficace. Le deuxième est que le mandat initial de L'ANSI C était de principalement codifier comportement existant plutôt que d'inventer comportement Nouveau , et ces décisions de conception ont été prises bien avant que L'ANSI n'entame le processus. Même L'ISO fait aujourd'hui preuve d'une grande prudence lorsqu'il s'agit de modifier les règles existantes dans les normes.

quant à la façon de gérer 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 sur stdout , pour le régler à unbuffered et vous n'aurez pas à vous soucier d'ajouter toutes ces lignes fflush à votre code:

setvbuf (stdout, NULL, _IONBF, BUFSIZ);

il suffit de garder à l'esprit qui peut affecter la performance un peu si vous sont l'envoi de la sortie à un fichier. Gardez également à l'esprit que le soutien à cet égard est défini par la mise en œuvre, et non garanti par la norme.

section ISO C99 7.19.3/3 est le bit pertinent:

Lorsqu'un flux est Non tamponné , les caractères sont destinés à apparaître à partir de la source ou à la destination dès que possible. Dans le cas contraire, les caractères peuvent être accumulés et transmis à l'environnement hôte ou à partir de celui-ci sous forme de bloc.

Lorsqu'un flux est entièrement tamponné , les caractères sont destinés à être transmis vers ou depuis l'environnement hôte sous forme de bloc quand un tampon est rempli.

Lorsqu'un flux est tampon de ligne , les caractères sont destinés à être transmis vers ou depuis l'environnement hôte sous forme de bloc lorsqu'un caractère de nouvelle ligne est rencontré.

de plus, les caractères sont destinés à être transmis en bloc à l'environnement hôte lorsqu'un tampon est rempli, lorsque l'entrée est demandée sur un flux non-tamponné, ou lorsque l'entrée est demandée sur un flux tamponné par ligne . cela nécessite la transmission de caractères depuis l'environnement hôte.

le Support de ces caractéristiques est défini par la mise en œuvre et peut être affecté par les fonctions setbuf et setvbuf .

103
répondu paxdiablo 2010-11-17 03:58:08

c'est probablement comme ça à cause de l'efficacité et parce que si vous avez plusieurs programmes écrivant à un seul TTY, de cette façon vous ne recevez pas les caractères sur une ligne entrelacée. Donc si les programmes A et B sortent, vous obtiendrez habituellement:

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

ça 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 de tirer la chasse d'eau sur une nouvelle ligne, vous devez donc tirer la chasse d'eau explicitement si cela vous importe.

22
répondu Southern Hospitality 2009-11-11 17:54:06

pour rincer immédiatement appeler fflush(stdout) ou fflush(NULL) ( NULL signifie tout rincer).

19
répondu Aaron 2015-09-25 01:10:09

Note: les bibliothèques Microsoft runtime ne prennent pas en charge la mise en tampon de ligne, donc printf("will print immediatelly to terminal") :

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

11
répondu Renato 2013-10-14 20:36:47

stdout est doté d'une mémoire tampon, de sorte que la sortie ne se fera qu'après l'impression d'une nouvelle ligne.

pour obtenir une sortie immédiate, soit:

  1. Imprimer vers stderr.
  2. faire stdout Non tamponné.
10
répondu Douglas Leeder 2009-11-11 16:25:08

par défaut, stdout est doté d'un tampon de ligne, stderr n'est pas doté d'un tampon et file est complètement doté d'un tampon.

10
répondu woso 2010-07-29 02:02:19

vous pouvez fprintf à stderr, qui est non rembourré, à la place. Ou vous pouvez jeter stdout quand vous voulez. Ou vous pouvez régler stdout à unbuffered.

8
répondu Rasmus Kaj 2009-11-11 16:26:49

utiliser setbuf(stdout, NULL); pour désactiver le tampon.

6
répondu dnahc araknayirp 2015-05-31 03:22:52