2010-10-19 28 views
2

Lorsque ce programme est exécuté, la ligne "stderr" est affichée avant la ligne "stdout". Pourquoi? Je pensais que dup2 ferait que stderr et stdout utilisent le même descripteur de fichier, donc il ne devrait pas y avoir de problème avec la mise en mémoire tampon. J'utilise gcc 3.4.6 sur Solaris 10.Problème avec dup2, stdout et stderr

#include <errno.h> 
#include <stdio.h> 
#include <unistd.h> 

int main() 
{ 
    int fd[2]; 
    int pid; 
    char buf[256]; 
    int n; 

    if(pipe(fd) < 0) { 
     perror("pipe"); 
     return 1; 
    } 
    if((pid = fork()) < 0) { 
     perror("fork"); 
     return 1; 
    } 
    else if(pid > 0) { // parent 
     close(fd[1]); 
     if((n = read(fd[0], buf, sizeof(buf))) > 0) { 
      buf[n] = 0; 
      printf("%s", buf); 
     } 
    } 
    else { 
     dup2(fd[1], fileno(stdout)); 
     dup2(fd[1], fileno(stderr)); 
     close(fd[1]); 
     fprintf(stdout,"stdout\n"); 
     fprintf(stderr,"stderr\n"); 
    } 
    return 0; 
} 

Répondre

3

Qu'en est-il de la vidange stdout?

dup2(fd[1], fileno(stdout)); 
dup2(fd[1], fileno(stderr)); 
close(fd[1]); 
fprintf(stdout,"stdout\n"); 
fflush(stdout); 
fprintf(stderr,"stderr\n"); 

(juste essayé et il fonctionne)

+0

Oui, je sais comment résoudre le problème. Je ne comprends tout simplement pas le comportement. Si stdout et stderr utilisent le même descripteur de fichier, je pense que la mise en mémoire tampon ne devrait pas poser de problème. –

+0

Je ne pense pas qu'il existe de norme précise à ce sujet .. Je veux dire que le noyau OS va gérer les choses en interne comme il le souhaite de toute façon .. – Jack

4

stdout deux cours d'eau et stderr peuvent utiliser le même descripteur de fichier, mais avant un flux de fichier écrit toutes les données à son descripteur de fichier sous-jacent, les données sont stockées dans le tampon du flux. Les tampons dans stdout et stderr ne deviennent pas identiques simplement parce que les deux flux sont connectés au même descripteur de fichier.

Notez que cette mise en mémoire tampon est effectuée par les flux FILE dans la bibliothèque stdio, et non par le noyau du système d'exploitation et ses descripteurs de fichiers. Il peut y avoir une autre mise en mémoire tampon, mais ce problème est dû au niveau de la bibliothèque stdio ci-dessus.

+0

Merci. J'étais confus au sujet de la différence entre les flux et les descripteurs de fichiers. –

7

Il existe une différence entre les stdout FILE * s et stderr et les descripteurs de fichiers 1 et 2. Dans ce cas, ce sont les FICHIERS qui provoquent le comportement auquel vous ne vous attendiez pas. stderr n'est pas mis en mémoire tampon par défaut, de sorte qu'en cas d'erreur, vous pouvez imprimer le message de la manière la plus fiable, même si les performances de cette impression ralentissent les performances globales du programme.

stdout, par défaut, est mis en mémoire tampon. Cela signifie qu'il a un tableau de mémoire qu'il stocke les données que vous lui avez demandé d'écrire. Il attend jusqu'à ce que le tableau (appelé un tampon) soit rempli à un certain niveau ou (s'il est configuré pour la mise en mémoire tampon de ligne, ce qui est souvent le cas) jusqu'à ce qu'il voit un '\n'. Vous pouvez appeler fflush(stdout); pour le faire aller de l'avant et imprimer, cependant.

Vous pouvez modifier les paramètres de mise en mémoire tampon de FILE *. man 3 setbuf a les fonctions qui font cela pour vous. Dans votre exemple, le tampon stdout contenait la chaîne "stdout" pendant que le "stderr" était écrit à l'écran. Puis, à la sortie du programme, tous les fichiers ouverts FILE * sont rincés, de sorte que "stdout" est alors imprimé.