Travailler avec les flux standard d'entrée/sortie est la pierre angulaire de la programmation en C.
Historique de la question
La première implémentation de stdio en C (via <stdio.h>) prévoyait l'existence de trois flux standard : stdin (entrée standard), stdout (sortie standard) et stderr (flux d'erreurs standard). Ces flux permettent d'écrire un code portable pour interagir avec l'utilisateur et des outils d'automatisation.
Problème
Tout le monde ne connaît pas les subtilités : les flux peuvent être redirigés, la mise en mémoire tampon varie, une mauvaise manipulation des tampons ou l'ordre de fermeture peut entraîner des pannes inattendues et des pertes de données.
Solution
Toutes les fonctions standard d'entrée/sortie fonctionnent par défaut avec stdin, stdout ou stderr. Elles peuvent être redirigées par le système d'exploitation (par exemple, par une commande dans le shell), ainsi que dans le programme lui-même - via freopen ou setvbuf pour gérer la mise en mémoire tampon.
Exemple de code (redirection stdout vers un fichier) :
#include <stdio.h> int main() { FILE *fp = freopen("output.txt", "w", stdout); if (!fp) { perror("échec de freopen"); return 1; } printf("Cela ira dans le fichier output.txt! "); fclose(fp); // On ferme ! Il peut être nécessaire de fermer explicitement stdout return 0; }
Caractéristiques clés :
Peut-on passer les descripteurs stdin, stdout ou stderr à d'autres processus et faire ce qu'on veut avec ?
Seulement si le système d'exploitation prend en charge l'héritage des descripteurs (par exemple, en Unix via fork), mais ce n'est pas toujours correct, surtout lors de la combinaison des entrées/sorties basse niveau (read/write) et de stdio (fgets/printf) — une incohérence des tampons est possible.
Est-il nécessaire de vider manuellement (flush) stdout et stderr ?
Pour stdout, un vidage (fflush) est nécessaire si l'on veut s'assurer que les données sont écrites immédiatement (par exemple, avant une sortie d'urgence). stderr est généralement non tamponné, sa sortie se fait immédiatement.
Que se passe-t-il si l'on ne ferme pas le stdout redirigé par freopen ?
Une partie des données peut être perdue en raison d'un tampon non vidé ! Il est important de fermer explicitement le flux (fclose) ou de faire fflush(stdout) avant de terminer le programme.
Exemple de code :
fclose(stdout); // cela provoquera un vidage du tampon et fermera le flux
Avantages : Interface unifiée, mise en mémoire tampon pour la vitesse, facile à remplacer la sortie pendant les tests
Inconvénients : Perte de données en raison d'un fflush/fclose oublié, confusion en combinant stdio et io basse niveau, perte de visibilité des erreurs lorsque stdout et stderr sont redirigés
Cas négatif : Un utilitaire de test redéfinit stdout et oublie ensuite de fermer le flux - 20% des résultats dans le fichier sont perdus. Avantages : rien à changer dans le reste du code, inconvénients : perte de données et diagnostic difficile.
Cas positif : Le programme génère des rapports sur stdout et des erreurs sur stderr, pour le débogage, stderr va toujours immédiatement (sans tampon), à la fin du bloc de rapport, on effectue fflush(stdout). Avantages : réaction rapide aux erreurs, enregistrement fiable des rapports ; inconvénients : nécessite une discipline de travail avec les tampons.