53 votes

C ++: redirection de STDOUT

Dans mon application, je souhaite rediriger la sortie qui irait normalement vers le flux stdout vers une fonction que je définis. J'ai lu que vous pouvez rediriger stdio vers un fichier, alors pourquoi pas vers une fonction?

Par exemple:

 void MyHandler( const char* data );

//<<Magical redirection code>>

printf( "test" );
std::cout << "test" << std::endl;

//MyHandler should have been called with "test" twice, at this point
 
  • Comment puis-je obtenir ce comportement / similaire?

48voto

zpasternack Points 10563

@Konrad Rudolph est à droite, vous pouvez tout à fait faire cela, facilement, à moins de cout/eree/boucher. Vous n'avez même pas besoin de votre propre streambuf mise en œuvre, il suffit d'utiliser une ostringstream.

// Redirect cout.
streambuf* oldCoutStreamBuf = cout.rdbuf();
ostringstream strCout;
cout.rdbuf( strCout.rdbuf() );

// This goes to the string stream.
cout << "Hello, World!" << endl;

// Restore old cout.
cout.rdbuf( oldCoutStreamBuf );

// Will output our Hello World! from above.
cout << strCout.str();

Même chose travaille pour eree et de boucher, mais dans mon expérience, cela ne marchera PAS dans stdout/stderr en général, de sorte printf ne sera pas sortie de là. cout va vers la sortie standard, mais rediriger le cout ne sera pas rediriger toutes les stdout. Au moins, c'était mon expérience.

Si la quantité de données devrait être petit, le freopen/setbuf chose fonctionne bien. J'ai fini par faire l'amateur dup/dup2 chose de la redirection vers un tuyau.

Mise à jour: j'ai écrit un post de blog montrant la dup2 méthode que j'ai fini par utiliser, dont vous pouvez lire ici. Il est écrit pour OS X, mais peuvent travailler dans d'autres systèmes d'exploitation Unix. Je doute sérieusement qu'il serait de travailler dans Windows. Le cacao version de la même chose ici.

10voto

Konrad Rudolph Points 231505

Toutes les autres réponses sont fausses. Vous pouvez le faire, et vous n'avez pas besoin de recourir à l' freopen,, ni à aucun autre C ou non des fonctions.

Au lieu de cela, vous devez créer votre propre std::streambuf mise en œuvre, c'est à dire votre propre mémoire tampon du flux.

Une fois que vous avez cela, vous pouvez rediriger l' cout flux par la commutation de la mémoire tampon:

your_stream_buffer new_buffer;
streambuf* old_buffer = cout.rdbuf(&new_buffer);

cout << "Hello"; // This will be redirected to `new_buffer`.

// Restore original buffer:
cout.rdbuf(old_buffer);

Depuis je ne l'ai jamais fait moi-même, je ne peux pas vous dire exactement comment la mise en œuvre de l' streambuf a ressembler. Mon conseil est d'avoir un coup d'oeil à la documentation et faites un mannequin de mise en œuvre qui imprime de diagnostic pour toutes les fonctions mises en place. Cela devrait vous aider à comprendre comment la classe fonctionne.

Sinon, jetez un oeil à une C++ ouvrage de référence de votre choix qui décrit l' streambuf classe.

6voto

Wang Xuancong Points 1

Il est possible de désactiver stdin / stdout en déréférencant son pointeur:

 FILE fp_old = *stdout;  // preserve the original stdout
*stdout = *fopen("/dev/null","w");  // redirect stdout to null
HObject m_ObjPOS = NewLibraryObject(); // call some library which prints unwanted stdout
*stdout=fp_old;  // restore stdout
 

4voto

stefan Points 2244

Réponse: Oui, vous pouvez, via une dup. freopen ne rouvrira stdout que dans un fichier, comme vous en avez parlé.

Découvrez comment mettre en mémoire tampon stdout en mémoire et l'écrire à partir d'un thread dédié

1voto

wilhelmtell Points 25504

L' std::cout objet a une signification fixe, et c'est à la sortie du standard de flux. L'utilisateur de votre programme peut contrôler où la norme est connecté, pas vous. Ce que vous pouvez faire est de décider si vous voulez écrire dans un fichier, à la norme ou à tout autre flux de sortie. Donc, dans votre code, vous passer ce flux que vous écrivez.

Encore une fois, le point de l'écriture, de la standard volet est de donner à l'utilisateur une flexibilité dans le choix de l'emplacement de la sortie passe à. Vous n'êtes pas censé rediriger standard; c'est quelque chose que l'utilisateur est censé avoir la liberté de le faire.

Une autre chose est que vous ne devriez pas mélanger C IO et C++ IO dans un programme C++. Choisir les IO de la bibliothèque que vous souhaitez travailler et de s'y tenir.

Cela dit, vous pouvez en C++ assez élégamment commutateur de flux pour une fonction à partir de par le template de la fonction de gestionnaire sur les paramètres du modèle de std::basic_istream<>. Ensuite, la fonction va lire son entrée à partir du flux d'entrée indépendamment du type réel de flux de travail avec. Voici un exemple:

#include<iostream>
#include<fstream>
#include<string>

template<class Ch, class Tr>
void dodge_this(std::basic_istream<Ch, Tr>& in)
{
    // in is an input stream. read from it as you read from std::cin.
}

int main(int argc, char* argv[])
{
    if( std::string(argv[1]) == "cin" ) {
        dodge_this(std::cin);
    } else if( std::string(argv[1]) == "file" ) {
        std::ifstream file("input.txt");
        dodge_this(file);
    } else {
        dodge_this(dev_null_stream);  // i just made that up. you get the idea.
    }
}

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