informatique (MP2I/MPI) · Chapitre 8 · Application directe du cours
Deux sorties, deux destins
Mémoire, fichiers et entrées-sorties · niveau 2
Énoncé
Ce programme écrit alternativement sur les deux sorties. On l'exécute deux fois : une fois vers le terminal, une fois avec ./prog > tout.txt 2>&1. Les deux sorties sont-elles dans le même ordre ?
for (int i = 0; i < 3; i = i + 1) {
printf("resultat %d\n", i);
fprintf(stderr, "trace %d\n", i);
}Corrigé
Non, et la mesure est catégorique. Au terminal, les six lignes s'entrelacent dans l'ordre du programme. Redirigées ensemble dans un fichier, elles sortent ainsi :
trace 0
trace 1
trace 2
resultat 0
resultat 1
resultat 2
Toutes les traces avant tous les résultats, alors que le programme les a écrites en alternance.
La cause est le tamponnage, et il dépend de la destination :
| Flux | Vers un terminal | Vers un fichier ou un tube |
|---|---|---|
stdout | tampon de ligne | tampon de bloc (8 ko ici) |
stderr | aucun tampon | aucun tampon |
Redirigé, stdout accumule ses trois lignes dans son tampon et ne les écrit qu'à la fin du programme ; stderr écrit immédiatement. D'où l'inversion.
Ce n'est pas un défaut, c'est le contrat : la sortie d'erreur doit parvenir même si le programme est tué à l'instant suivant — un message d'erreur perdu dans un tampon ne sert à rien. Le prix est cet ordre trompeur, et il coûte cher en mise au point : on croit lire une chronologie, on lit deux chronologies superposées.
Les deux parades. Séparer les flux — > res.txt 2> err.txt — ce qui rend chaque fichier lisible et est la raison d'être des deux sorties ; ou forcer l'écriture par fflush(stdout) avant chaque trace, ce qui rétablit l'ordre au prix d'un appel système par ligne.