![]() |
|
ostream to printf |
kazzmir
Member #1,786
December 2001
![]() |
I debug my program by putting in statements like debug(0) << "Hello" or debug(1) << "hello" where the number passed in is the debug level. 0 is normal, 1 is slightly more verbose, etc. I accomplish this with the following code 1#include "debug.h"
2#include <iostream>
3
4using namespace std;
5
6static int global_debug_level = 0;
7
8class nullstreambuf_t: public std::streambuf {
9public:
10 nullstreambuf_t():std::streambuf(){
11 }
12};
13
14static nullstreambuf_t nullstreambuf;
15
16class nullcout_t: public std::ostream {
17public:
18 nullcout_t():std::ostream(&nullstreambuf){
19 }
20};
21
22static nullcout_t nullcout;
23
24ostream & Global::debug(int i, const string & context){
25 if ( global_debug_level >= i ){
26 std::cout << "[" << i << ":" << context << "] ";
27 return std::cout;
28 }
29 return nullcout;
30}
31
32void Global::setDebug( int i ){
33 global_debug_level = i;
34}
35
36int Global::getDebug(){
37 return global_debug_level;
38}
So either I return cout if the current debug level is less than or equal to the global debug level or I return an ostream object that sends all output to nowhere. Now I would like another ostream object that uses printf to print. This is because in the dolphin wii emulator it only recognizes output using printf but not cout. Supposedly I could hack the wii internals or some other crazy stuff to get cout to work but I haven't figured it out and I don't really want to. So can anyone figure out how to make an ostream object use printf? |
bamccaig
Member #7,536
July 2006
![]() |
You could implement your own std::ostream... Maybe you could do some crazy operator hacks to skip the actual implementation: class PrintfOstream: public std::ostream {}; PrintfOstream & operator<<(PrintfOstream & stream, const std::string & s) { // Dodge velociraptor attack... printf(s.c_str()); return stream; } I'm not sure if that would work or not ... -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
kazzmir
Member #1,786
December 2001
![]() |
Hm ok I tried that before and it didn't work for some reason but I can't remember why now. I'll try this again and see how far I get. |
bamccaig
Member #7,536
July 2006
![]() |
1#include <fstream>
2#include <iostream>
3#include <sstream>
4#include <string>
5
6class PrintfOstream: public std::ostream {};
7
8PrintfOstream & operator<<(PrintfOstream & stream, const std::string & s)
9{
10 std::cerr << "Called my special operator... \\o/" << std::endl;
11
12 // Dodge velociraptor attack...
13 printf(s.c_str());
14
15 return stream;
16}
17
18PrintfOstream & operator<<(PrintfOstream & stream, const char * const s)
19{
20 return stream << std::string(s);
21}
22
23PrintfOstream & operator<<(PrintfOstream & stream, std::ostream & (*f)(std::ostream &))
24{
25 std::stringstream ss;
26
27 ss << f;
28
29 return stream << ss.str();
30}
31
32int main(int argc, char * argv[])
33{
34 PrintfOstream cout;
35
36 cout << "Hurray!" << std::endl;
37}
bash $ g++ -Wall main.cpp bash $ ./a.out 2>/dev/null Hurray! bash $ ./a.out 1>/dev/null Called my special operator... \o/ Called my special operator... \o/ bash $
-- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
Evert
Member #794
November 2000
![]() |
Quote: So can anyone figure out how to make an ostream object use printf?
You can use fprintf() to print to a (C) stream. Not sure if that helps. |
bamccaig
Member #7,536
July 2006
![]() |
^ That's another very reasonable solution. TBH, the printf family is nicer than iostream except that iostream can be extended to deal with user-defined types in C++. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
Karadoc ~~
Member #2,749
September 2002
![]() |
I'm a great fan of printf; and when I want to use the awesomeness of printf alongside the safety/convenience of c++ features, I use boost::format. ----------- |
bamccaig
Member #7,536
July 2006
![]() |
boost::format is nice, but it's sort of a compromise. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
ImLeftFooted
Member #3,935
October 2003
![]() |
The simplest way is to using ostringstream and forward the whole thing to printf as a string (ie printf("%s", myStream.str().c_str())). Figuring out when to execute the print is the hard part IIRC. I'll update my post with an example. Okay, I thought of the dead simple solution. 1#include <sstream>
2
3class Debug {
4public:
5bool ignore;
6template<class T>
7Debug operator <<(const T &t)
8{
9 if(ignore) return *this;
10
11 ostringstream ss;
12
13 ss << t;
14
15 string s = ss.str();
16 // Copy string object become some compilers *cough*MSVC*cough*
17 // have faulty temporary object issues that break c_str() w/o this.
18
19 printf("%s", s.c_str());
20
21 return *this;
22}
23};
24
25Debug Global::debug(int i, const string & context){
26 Debug ret;
27 ret.ignore = true;
28 if ( global_debug_level >= i ){
29 printf("[%d:%s] ", i, context.c_str());
30 ret.ignore = false;
31 }
32 return ret;
33}
It wont group your cout statements into a single printf -- but your old code didn't do that anyway. Update: Darn, beaten by bamccaig and his answer was more correct |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
bam-boy said:
PrintfOstream & operator<<(PrintfOstream & stream, std::ostream & (*f)(std::ostream &)) { std::stringstream ss; ss << f; return stream << ss.str(); }
What the hell is that? Why would you overload the stream out operator to accept a specialized function pointer that you don't even call? And you don't need to use a stringstream to send a pointer to an ostream. Edit bammer said:
PrintfOstream & operator<<(PrintfOstream & stream, const std::string & s) { std::cerr << "Called my special operator... \\o/" << std::endl; // Dodge velociraptor attack... failed dexterity check... eaten! return stream; }
You don't want to directly pass the string to printf, otherwise it could interpret the string as commands. Use %s instead : printf("%s" , s.c_str());
My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
bamccaig
Member #7,536
July 2006
![]() |
@Dustin Dettmer: Your fail in indentation is inexecusable[1] given your experience with the community. I award you no points. May <insert_deity_here> have mercy on your soul. Edgar Reynaldo said:
What the hell is that? Why would you overload the stream out operator to accept a specialized function pointer that you don't even call? And you don't need to use a stringstream to send a pointer to an ostream. See std::endl. I'm not sure that I handled it in the most optimized/best way possible, but I do welcome you to correct me (note that I didn't bother checking if e.g., std::hex required more). Edgar Reynaldo said: You don't want to directly pass the string to printf, otherwise it could interpret the string as commands.
Good catch. References
-- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
Dustin, you're returning a reference to a stack object that goes out of scope. If you're going to use bamccaig's implementation, you will have to make it (your PrintfOstream object) a member of your debug class or else make it a global. The reason is that you can't call it through an ostream* and expect it to work the same way, because operator << is not virtual, so if you call it from an ostream * or & then you get the ostream implementations of operator <<. I can't believe I'm saying this, but I actually learned something from bamccaig. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
ImLeftFooted
Member #3,935
October 2003
![]() |
Edgar Reynaldo said: Dustin, you're returning a reference to a stack object that goes out of scope. Simple mistake, fixed now. Bam's solution still looks better on the surface. |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
Dustin Dettmer said: Bam's solution still looks better on the surface. Not without some help from your implementation. His only handles strings and manipulators. Yours handles all the other types of data. If you want to be able to affect the stream with manipulators, then you need to have a persistent stream to affect, not a temporary one. The best of both worlds : LogStream.hpp 1
2#ifndef LogStream_H
3#define LogStream_H
4
5#include <iostream>
6using std::ostream;
7
8#include <sstream>
9using std::stringstream;
10
11#include <string>
12using std::string;
13
14#include <cstdio>
15
16enum DEBUG_LEVEL {
17 NONE = 0,
18 ERROR = 1,
19 WARNING = 2,
20 INFO = 3,
21 VERBOSE = 4
22};
23
24extern DEBUG_LEVEL global_debug_level;
25
26class pfostream : virtual public std::ostream {
27private :
28 stringstream ss;
29
30public :
31 pfostream() : ss() {}
32
33 template <class Type>
34 pfostream& operator<<(const Type& t);
35
36 pfostream& operator<<(ostream& (*f)(ostream&));
37};
38
39template <class Type>
40pfostream& pfostream::operator<<(const Type& t) {
41 ss.str("");
42 ss << t;
43 string s = ss.str();
44 printf("%s" , s.c_str());
45 return *this;
46}
47
48
49pfostream& pfostream::operator<<(ostream& (*f)(ostream&)) {
50 ss.str("");
51 ss << f;
52 string s = ss.str();
53 printf("%s" , s.c_str());
54 return *this;
55}
56
57
58class Logger {
59private :
60 DEBUG_LEVEL debug_level;
61 ostream* out;
62 pfostream* pfout;
63 bool use_pf;
64
65public :
66 Logger() : debug_level(ERROR) , out(0) , pfout(0) , use_pf(false) {}
67
68 void SetOstream(ostream* output) {
69 out = output;
70 use_pf = false;
71 }
72 void SetPfostream(pfostream* output) {
73 pfout = output;
74 use_pf = true;
75 }
76
77 template <class Type>
78 Logger& operator<<(const Type& t);
79
80 Logger& operator<<(ostream& (*f)(ostream&)) {
81 if (use_pf) {
82 if (!pfout) {return *this;}
83 *pfout << f;
84 } else {
85 if (!out) {return *this;}
86 *out << f;
87 }
88 return *this;
89 }
90};
91
92template <class Type>
93Logger& Logger::operator<<(const Type& t) {
94 if (use_pf) {
95 if (!pfout) {return *this;}
96 } else {
97 if (!out) {return *this;}
98 }
99 if (debug_level == NONE || global_debug_level == NONE) {return *this;}
100 if (debug_level <= global_debug_level) {
101 if (use_pf) {
102 *pfout << t;
103 } else {
104 *out << t;
105 }
106 }
107 return *this;
108}
109
110template <>
111Logger& Logger::operator<<(const DEBUG_LEVEL& t) {
112 debug_level = t;
113 return *this;
114}
115
116
117
118#endif
LogStream.cpp 1#include "LogStream.hpp"
2
3using std::cout;
4using std::endl;
5
6DEBUG_LEVEL global_debug_level = ERROR;
7
8
9
10int main(int argc , char** argv) {
11
12 pfostream pfout;
13 Logger logger;
14
15 logger << ERROR;
16 logger << "This won't be printed because the logger's output is null.";
17 logger << endl;
18
19 logger.SetOstream(&cout);
20 logger << ERROR << "Printing error to cout..." << endl;
21
22 logger.SetPfostream(&pfout);
23 logger << ERROR << "Printing error using printf..." << endl;
24
25
26 return 0;
27}
And if you want to pipe your log to a file, you should be able to use SetOstream to set it to the address of an ofstream object. That works in my library at least, even if using the address of a pfostream object doesn't. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
|