pourquoi l'appel système close() vidant la sortie ?
Question
Voici mon code :
#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
int main(int argc,char *argv[])
{
int oldfd;
int newfd;
if(argc!=2)
{
printf("Usgae : %s file_name\n",argv[0]);
exit(0);
}
oldfd=open(argv[1],O_RDWR|O_APPEND,S_IRWXU); // Opening the file in Read/Write mode
if (-1 == oldfd)
{
perror("Error opening file");
exit(0);
}
close(1); // closing stdout
newfd=dup(oldfd); //Now this newfd holds the value 1
close(oldfd); //closing the oldfd
printf("\nStack Overflow"); //Now this printf will print content into the file as stdout closed already
close(newfd);// closing newfd
return 0;
}
Ce que j'essaie en fait de faire, c'est simplement d'imprimer "Stack Overflow" dans le fichier en utilisant printf() au lieu de l'appel système write().
Il n'imprime pas le contenu dans le fichier.Mais une chose que j'ai observée est que si je supprime le code :
close(newfd)
Il imprime le contenu dans le fichier comme prévu.Mais je n'arrive pas à comprendre pourquoi.J'ai imprimé le contenu et ensuite seulement je ferme le newfd.
Quelle en est la raison ?
La solution
Ce qui se passe réellement ici, c'est que printf
La sortie de est mise en mémoire tampon et n'est pas envoyée immédiatement à fd 1 ;à la place, le tampon est vidé vers le descripteur de fichier 1 par le runtime C après votre retour de main
.Si tu close(newfd)
, vous avez effectivement obstrué le vidage automatique qui est autrement effectué par le runtime à la sortie.
Si vous explicitement fflush(stdout)
Avant toi close(newfd)
, votre sortie devrait apparaître dans le fichier.
À propos, si vous souhaitez rediriger un descripteur de fichier spécifique, il existe un autre appel système dup2(oldfd, 1)
ce qui fait de fd 1 un double de oldfd
, fermant le fd 1 s'il était précédemment ouvert.
Autres conseils
Lorsque vous utilisez directement des descripteurs de fichiers, vous voudrez éviter d'utiliser les fonctions C stdio telles que printf
.Changer le descripteur de fichier sous-jacent de sous la couche stdio semble très périlleux.
Si vous modifiez votre générique code-étiquette comme suit:
write(newfd, "\nStack Overflow", 15);
alors vous obtiendrez probablement le résultat que vous attendez (que ce soit votre printf
ou non).
close
, write
, open
sont appels système principalement fait à l'intérieur du noyau Linux;donc du point de vue applicatif, ce sont des opérations atomiques élémentaires.
printf
et fprintf
sont des fonctions de bibliothèque standard construites au-dessus de ces appels système (et d'autres).
Avant sortie-ing (par ex.revenant de main
), la bibliothèque standard et l'environnement (notamment le code dans crt*.o
appeler votre main
) exécute les fonctions enregistrées par une sortie;et l'E/S standard enregistre (en quelque sorte) un appel à affleurer à l'heure de la sortie.Alors le stdout
est fflush
-ed à l'heure de sortie.Si tu close
son descripteur principal, ce vidage échoue et ne fait rien.
je pense qu'il ne faut pas mélanger stdio
et cru write
-s au même descripteur d'écriture.Pensez à utiliser fdopen
ou freopen