673 votes

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 n'est-il pas vide après l'appel, sauf si un retour à la ligne est dans la chaîne de format? Est-ce un comportement POSIX? Comment pourrais-je avoir printf immédiatement à chaque fois?

879voto

Rudd Zwolinski Points 6852

L' stdout flux est mis en mémoire tampon, de sorte affichera uniquement ce qui est dans le buffer après avoir atteint un saut de ligne (ou quand c'est dit). Vous avez un peu d'options pour imprimer immédiatement:

Imprimer vers stderr l'aide d' fprintf:

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

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

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

Edit: De Andy Ross commentaire ci-dessous, vous pouvez également désactiver la mise en mémoire tampon sur la sortie standard en utilisant setbuf:

setbuf(stdout, NULL);

145voto

paxdiablo Points 341644

Non, il n'est pas POSIX comportement, c'est de l'ISO comportement (bon, c' est POSIX comportement, mais seulement dans la mesure où ils sont conformes à la norme ISO).

La sortie Standard est la ligne de tampon si elle peut être détectée à se référer à un dispositif interactif, sinon il est entièrement mis en mémoire tampon. Il y a des situations où l' printf ne pas rincer, même s'il fait un retour à la ligne pour envoyer, tels que:

myprog >myfile.txt

Cela a un sens pour l'efficacité car, si vous êtes en interaction avec un utilisateur, ils veulent probablement pour voir chaque ligne. Si vous êtes à envoyer la sortie vers un fichier, il est plus que probable qu'il n'y a pas un utilisateur à l'autre bout (mais pas impossible, ils pourraient être de résidus de la file). Maintenant, vous pourriez argumenter que l'utilisateur veut les voir chaque personnage, mais il y a deux problèmes avec ça.

La première est qu'il n'est pas très efficace. La deuxième est que le C ANSI mandat avait pour principal objet de codifier existant comportement, plutôt que d'inventer de nouveaux comportements, et ceux de la conception des décisions ont été prises bien avant ANSI a commencé le processus. Même ISO de nos jours de marches très attentivement lors de la modification des règles existantes dans les normes.

Quant à la façon de traiter avec cela, si vous fflush (stdout) après chaque sortie que vous souhaitez voir immédiatement, qui permettra de résoudre le problème.

Alternativement, vous pouvez utiliser setvbuf avant d'opérer sur stdout, pour le mettre en mémoire sans tampon et vous ne devez pas vous inquiéter au sujet de l'ajout de tous ces fflush des lignes de code:

setvbuf (stdout, NULL, _IONBF, BUFSIZ);

Il suffit de garder à l'esprit que peut affecter les performances tout à fait un peu si vous êtes d'envoyer la sortie vers un fichier. Aussi garder à l'esprit que le soutien à cette mise en œuvre est définie, non garantie par la norme.

La norme ISO C99 section 7.19.3/3 est le:

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

Lorsqu'un flux est entièrement mis en mémoire tampon, les personnages sont destinés à être transmis vers ou à partir de l'hôte de l'environnement comme un bloc lorsqu'un tampon est rempli.

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

En outre, les personnages sont destinés à être transmis comme un bloc à l'environnement d'accueil lorsqu'un tampon est rempli, lorsque la saisie est demandée sur un tampon de flux, ou lorsque la saisie est demandée sur une ligne de tampon de flux qui nécessite la transmission de caractères à partir de l'environnement d'accueil.

Le Support de ces caractéristiques est la mise en œuvre définies, et peut être affectée par l' setbuf et setvbuf fonctions.

34voto

C'est probablement comme ça à cause de l'efficacité et parce que si vous avez plusieurs programmes qui écrivent sur un seul TTY, vous n'obtenez pas de caractères sur une ligne entrelacée. Donc, si les programmes A et B sortent, vous aurez 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.

33voto

Aaron Points 5463

Pour vider immédiatement, appelez fflush (stdout) ou fflush (NULL) (NULL signifie que tout est vide).

14voto

Douglas Leeder Points 29986

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. Rendre stdout unbuffered.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X