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?
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);
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
etsetvbuf
.
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.
pour rincer immédiatement appeler fflush(stdout)
ou fflush(NULL)
( NULL
signifie tout rincer).
Note: les bibliothèques Microsoft runtime ne prennent pas en charge la mise en tampon de ligne, donc printf("will print immediatelly to terminal")
:
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:
- Imprimer vers stderr.
- faire stdout Non tamponné.
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.
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.
utiliser setbuf(stdout, NULL);
pour désactiver le tampon.