[Interest] QDebugStream quit working with Qt 4.8.0-rc1 and new compiler
K. Frank
kfrank29.c at gmail.com
Sat Nov 5 00:18:06 CET 2011
Hello Lists!
On Sun, Oct 30, 2011 at 6:09 PM, K. Frank <kfrank29.c at gmail.com> wrote:
> Hi List!
>
> I have been using QDebugStream, a utility class that I downloaded from
> the list archive, and it is no longer working.
I believe that I have a fix for the issue:
In short, in qdebugstream.h, the declaration of "pos" should be:
size_t pos;
rather than
unsigned pos;
(As I understand it, under 32-bit g++, "size_t" is essentially "unsigned,"
while under 64-bit g++, "size_t" is "unsigned long," a wider integral type,
explaining why the error shows up when moving to the 64-bit compiler.)
> I've upgraded to Qt 4.8.0-rc1, and a new compiler, the std::thread-enabled,
> 64-bit g++ 4.7.0 mingw-w64 build provided by the famous Ruben.
>
> Something broke QDebugStream along the way, and I can't figure out
> what the problem is.
>
> What do folks think the problem might be?
>
> Does Qt 4.8.0-rc1 have a bug?
The error seems to be entirely independent of Qt. I can duplicate the
problem in a test program that does not use Qt at all.
> Is the new (explicitly experimental) std::thread-enabled 4.7.0 compiler
> buggy?
(I believe that the original ("unsigned pos;") code is incorrect. However,
I do believe that there is a bug in how the 64-bit 4.7.0 compiler handles
the incorrect code. But that's another story...)
> Is there some bug (for example, some kind of undefined behavior) in
> QDebugStream that happens to work in the old environment, but not
> in the new?
As indicated above, there is a bug in the original qdebustrean.h code.
(I do not believe that this bug is undefined behavior. But that's another
story...)
For reference, I post the corrected qdebugstream.h below:
Also, I have quoted the entire original post so that the full context
shows up on the new list.
Thanks for everyone's suggestions.
K. Frank
The corrected qdebugstream.h:
====================
// qdebugstream.h 20.7.10
// version 1.1 4.11.11
// version 1.1: patch ("size_t pos") to fix 64-bit error
// from Jochen Ulrich 6.6.2005 posting to qt-interest at trolltech.com
// "Redirecting std::cout to QTextEdit / Using QTextEdit as a Log Window"
// http://lists.trolltech.com/qt-interest/2005-06/thread00166-0.html
// example usage from same posting:
// #include "qdebugstream.h"
// #include "qtextedit.h"
//
// void main( )
// {
// [...]
// QTexEdit* myTextEdit = new QTextEdit(this, "myTextEdit");
// myTextEdit->setTextFormat(Qt::LogText);
//
// QDebugStream qout(std::cout, myTextEdit);
// std::cout << "Send this to the Text Edit!" << endl;
//
// [...]
// }
//################
//# qdebugstream.h #
//################
#ifndef Q_DEBUG_STREAM_H
#define Q_DEBUG_STREAM_H
#include <iostream>
#include <streambuf>
#include <string>
#include "qtextedit.h"
class QDebugStream : public std::basic_streambuf<char>
{
public:
QDebugStream(std::ostream &stream, QTextEdit* text_edit) : m_stream(stream)
{
log_window = text_edit;
m_old_buf = stream.rdbuf();
stream.rdbuf(this);
}
~QDebugStream()
{
// output anything that is left
if (!m_string.empty())
log_window->append(m_string.c_str());
m_stream.rdbuf(m_old_buf);
}
protected:
virtual int_type overflow(int_type v)
{
if (v == '\n')
{
log_window->append(m_string.c_str());
m_string.erase(m_string.begin(), m_string.end());
}
else
m_string += v;
return v;
}
virtual std::streamsize xsputn(const char *p, std::streamsize n)
{
m_string.append(p, p + n);
// int pos = 0;
// unsigned pos = 0; // avoid conversion warnings
size_t pos = 0; // patch to avoid 64-bit conversion error
while (pos != std::string::npos)
{
pos = m_string.find('\n');
if (pos != std::string::npos)
{
std::string tmp(m_string.begin(), m_string.begin() + pos);
log_window->append(tmp.c_str());
m_string.erase(m_string.begin(), m_string.begin() + pos + 1);
}
}
return n;
}
private:
std::ostream &m_stream;
std::streambuf *m_old_buf;
std::string m_string;
QTextEdit* log_window;
};
#endif
====================
>
> Any ideas would be welcome!
>
> The point of QDebugStream is to redirect output sent to a std::ostream
> to a QTextEdit (e.g., a log window).
>
> In my simple test program, below, when working (that is, for example,
> when built with Qt 4.6.1 and a 32-bit tdm mingw g++ 4.4.1 compiler),
> both messages show up in the QTextEdit:
>
> Message 1 (with '\n')...
> Message 2 (with '\n')...
>
> But when built with 4.8.0-rc1 / 4.7.0, only the first message shows up:
>
> Message 1 (with '\n')...
>
> (Some further variations on this theme are given in the lines commented
> out, and should be relatively self-explanatory.)
>
> Before I give more details and the code, I have some comments:
>
> I have been using QDebugStream for a while now in a couple of different
> Qt / compiler environments, and it has seemed to work fine. The broken
> version (4.8.0-rc1 / 4.7.0) behaves as if only the first insertion operator
> for the redirected stream gets processed (and -- per QDebugStream's
> design -- only if the inserted text contains a '\n' does anything get displayed
> in the QTextEdit).
>
> When I try to debug QDebugStream (with the version of gdb that came
> bundled with the mingw-w32 4.7.0 compiler build), it appears that
> QDebugStream::xsputn() only gets called for the first insertion operator.
> But I'm somewhat confused by what the debugger shows: Stepping
> through QDebugStream::xsputn() (using next) doesn't follow the flow
> of control that I would expect, and based on both stepping through
> the code and on breakpoints that don't fire, QDebugStream::xsputn()
> doesn't appear to exit through its return statement!
>
> I am not an expert on iostream and std::basic_streambuf, but the
> QDebugStream code looks correct to me, at least as far as I can tell.
> Also, I have seen various other comments on the web from people
> who have used QDebugStream (with or without modification), so it
> does seem to work for people other than me.
>
> Lastly, a real possibility is that the new compiler and/or its iostream
> library is broken. I did, however, write a test program that doesn't touch
> Qt, but uses the technique of QDebugStream to redirect std::cout to
> an ofstream, and that worked fine. (However, I just did a simple
> "g++ -g" build of my non-Qt test program, so maybe one of the compiler
> switches set up by qmake is triggering a bug in wither the compiler or
> iostream library or Qt or QDebugStream.)
>
> Anyway, here are the details:
>
> The qmake / mingw32-make-generated compile and linking commands
> that build the broken version are:
>
> C:>qmake qdebugstream_test.pro
>
> C:>mingw32-make
> mingw32-make -f Makefile.Debug
> mingw32-make[1]: Entering directory `C:'
> g++ -c -g -frtti -fexceptions -mthreads -Wall -DUNICODE
> -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB
> -DQT_HAVE_MMX -DQT_HAVE_3DNOW -DQT_HAVE_SSE -DQT_HAVE_MMXEXT
> -DQT_HAVE_SSE2 -DQT_THREAD_SUPPORT -DQT_NEEDS_QMAIN
> -I"c:\4.8.0-rc1\include\QtCore" -I"c:\4.8.0-rc1\include\QtGui"
> -I"c:\4.8.0-rc1\include" -I"c:\4.8.0-rc1\include\ActiveQt" -I"debug"
> -I"c:\4.8.0-rc1\mkspecs\default" -o debug\qdebugstream_test.o
> qdebugstream_test.cpp
> g++ -mthreads -Wl,-subsystem,windows -o debug\qdebugstream_test.exe
> debug/qdebugstream_test.o -L"c\4.8.0-rc1\lib" -lmingw32 -lqtmaind
> -lQtGuid4 -lQtCored4
> mingw32-make[1]: Leaving directory `C:'
>
> C:>
>
>
> Here is my simple test program:
>
> ====================
>
> // qdebugstream_test.cpp
>
> // test / debug qdebugstream...
> // it is no longer working with g++ 4.7.0 and qt 4.8.0-rc1
>
> #include <iostream>
>
> #include <QApplication>
> #include <QtGui>
>
> #include "qdebugstream.h"
>
> int main (int argc, char *argv[]) {
> QApplication app (argc, argv);
> QTextEdit *text1 = new QTextEdit();
>
> QDebugStream *qout = new QDebugStream (std::cout, text1);
>
> if (qout) { // to avoid unused variable warning
> // prints neither message to text1
> // std::cout << "Message 1 (with endl)..." << std::endl;
> // std::cout << "Message 2 (with endl)..." << std::endl;
>
> // prints only "Message 1" to text1
> std::cout << "Message 1 (with '\\n')...\n";
> std::cout << "Message 2 (with '\\n')...\n";
>
> // prints both messages to text1
> // std::cout << "Message 1 (with two '\\n's)...\nMessage 2 (with
> two '\\n's)...\n";
> }
>
> text1->show();
> return app.exec();
> }
>
> ====================
>
> The associated .pro file is trivial:
>
> ====================
>
> # qdebugstream_test.pro
>
> HEADERS =
> SOURCES = qdebugstream_test.cpp
> FORMS =
>
> ====================
>
> I build the program by running:
>
> qmake
> mingw32-make
>
> Lastly, QDebugStream is defined and implemented in a single header file:
>
> ====================
>
> // qdebugstream.h 20.7.10
> // version 1.0 20.7.10
>
> // from Jochen Ulrich 6.6.2005 posting to qt-interest at trolltech.com
> // "Redirecting std::cout to QTextEdit / Using QTextEdit as a Log Window"
> // http://lists.trolltech.com/qt-interest/2005-06/thread00166-0.html
>
> // example usage from same posting:
>
> // #include "qdebugstream.h"
> // #include "qtextedit.h"
> //
> // void main( )
> // {
> // [...]
> // QTexEdit* myTextEdit = new QTextEdit(this, "myTextEdit");
> // myTextEdit->setTextFormat(Qt::LogText);
> //
> // QDebugStream qout(std::cout, myTextEdit);
> // std::cout << "Send this to the Text Edit!" << endl;
> //
> // [...]
> // }
>
>
> //################
> //# qdebugstream.h #
> //################
>
> #ifndef Q_DEBUG_STREAM_H
> #define Q_DEBUG_STREAM_H
>
> #include <iostream>
> #include <streambuf>
> #include <string>
>
> #include "qtextedit.h"
>
> class QDebugStream : public std::basic_streambuf<char>
> {
> public:
> QDebugStream(std::ostream &stream, QTextEdit* text_edit) : m_stream(stream)
> {
> log_window = text_edit;
> m_old_buf = stream.rdbuf();
> stream.rdbuf(this);
> }
> ~QDebugStream()
> {
> // output anything that is left
> if (!m_string.empty())
> log_window->append(m_string.c_str());
>
> m_stream.rdbuf(m_old_buf);
> }
>
> protected:
> virtual int_type overflow(int_type v)
> {
> if (v == '\n')
> {
> log_window->append(m_string.c_str());
> m_string.erase(m_string.begin(), m_string.end());
> }
> else
> m_string += v;
>
> return v;
> }
>
> virtual std::streamsize xsputn(const char *p, std::streamsize n)
> {
> m_string.append(p, p + n);
>
> // int pos = 0;
> unsigned pos = 0; // avoid conversion warnings
> while (pos != std::string::npos)
> {
> pos = m_string.find('\n');
> if (pos != std::string::npos)
> {
> std::string tmp(m_string.begin(), m_string.begin() + pos);
> log_window->append(tmp.c_str());
> m_string.erase(m_string.begin(), m_string.begin() + pos + 1);
> }
> }
>
> return n;
> }
>
> private:
> std::ostream &m_stream;
> std::streambuf *m_old_buf;
> std::string m_string;
> QTextEdit* log_window;
> };
>
> #endif
>
> ====================
More information about the Interest
mailing list