QT分析之調試跟蹤系統


原文地址:http://blog.163.com/net_worm/blog/static/127702419201002004518944/

 

在我們前面的分析中,經常看到qWarning()和qDebug()之類的調用。今天深入的分析QT的調試跟蹤系統。

我們先看QDebug.h中的宏定義:

 1 #if !defined(QT_NO_DEBUG_STREAM)
 2 Q_CORE_EXPORT_INLINE QDebug qDebug() { return QDebug(QtDebugMsg); }
 3 
 4 #else // QT_NO_DEBUG_STREAM
 5 #undef qDebug
 6 inline QNoDebug qDebug() { return QNoDebug(); }
 7 #define qDebug QT_NO_QDEBUG_MACRO
 8 
 9 #ifdef QT_NO_MEMBER_TEMPLATES
10 template<typename T>
11 inline QNoDebug operator<<(QNoDebug debug, const T &) { return debug; }
12 #endif
13 
14 #endif
15 
16 #if !defined(QT_NO_WARNING_OUTPUT)
17 Q_CORE_EXPORT_INLINE QDebug qWarning() { return QDebug(QtWarningMsg); }
18 #else
19 #undef qWarning
20 inline QNoDebug qWarning() { return QNoDebug(); }
21 #define qWarning QT_NO_QWARNING_MACRO
22 #endif

這里很明顯,QT的調試跟蹤系統就是兩條:DEBUG和WARNING。先看DEBUG,如果我們定義了宏QT_NO_DEBUG_STREAM,qDebug()被定義成QNoDebug(),而QT_NO_QDEBUG_MACRO的定義:

1 #define QT_NO_QDEBUG_MACRO if(1); else qDebug

注意if后面的分號,其等價於空語句。

我們再看QNoDebug類的定義:

 1 class QNoDebug
 2 {
 3 public:
 4     inline QNoDebug(){}
 5     inline QNoDebug(const QDebug &){}
 6     inline ~QNoDebug(){}
 7 #if !defined( QT_NO_TEXTSTREAM )
 8     inline QNoDebug &operator<<(QTextStreamFunction) { return *this; }
 9     inline QNoDebug &operator<<(QTextStreamManipulator) { return *this; }
10 #endif
11     inline QNoDebug &space() { return *this; }
12     inline QNoDebug &nospace() { return *this; }
13     inline QNoDebug &maybeSpace() { return *this; }
14 
15 #ifndef QT_NO_MEMBER_TEMPLATES
16     template<typename T>
17     inline QNoDebug &operator<<(const T &) { return *this; }
18 #endif
19 };

重載的<<操作只是返回其自身。另外一種情況(就是有DEBUG_STREAM)的時候,也就是缺省情況下,qDebug被定為QDebug,QDebug的輸出設備是什么呢?看QDebug類中構造的定義:

1     inline QDebug(QIODevice *device) : stream(new Stream(device)) {}
2     inline QDebug(QString *string) : stream(new Stream(string)) {}
3     inline QDebug(QtMsgType t) : stream(new Stream(t)) {}
4     inline QDebug(const QDebug &o):stream(o.stream) { ++stream->ref; }


可以知道QDebug的輸出設備可以使QString,QIODevice或者QtMsgType指定的類型。

如果我們在main()函數里面寫這樣一行程序:

1 qDebug() << "Hello world!";

其執行的效果是向stderr設備輸出"Hello world!",根據

1 Q_CORE_EXPORT_INLINE QDebug qDebug() { return QDebug(QtDebugMsg); }

定義,實際調用的是:

1 inline QDebug(QtMsgType t) : stream(new Stream(t)) {}

語句,在新生成Stream對象的時候,調用的是:

1 Stream(QtMsgType t) : ts(&buffer, QIODevice::WriteOnly), ref(1), type(t), space(true), message_output(true) {}

執行完畢之后,會釋放QDebug對象,看看QDebug的釋放:

 

1 inline ~QDebug() {
2         if (!--stream->ref) {
3             if(stream->message_output)
4                 qt_message_output(stream->type, stream->buffer.toLocal8Bit().data());
5             delete stream;
6         }
7     }

我們再來看qt_message_output()的代碼:

 

 1 void qt_message_output(QtMsgType msgType, const char *buf)
 2 {
 3     if (handler) {
 4         (*handler)(msgType, buf);
 5     } else {
 6 #if defined(Q_CC_MWERKS)
 7         mac_default_handler(buf);
 8 #elif defined(Q_OS_WINCE)
 9         QString fstr = QString::fromLatin1(buf);
10         fstr += QLatin1String("\n");
11         OutputDebugString(reinterpret_cast<const wchar_t *> (fstr.utf16()));
12 #else
13         fprintf(stderr, "%s\n", buf);
14         fflush(stderr);
15 #endif
16     }
17 
18     if (msgType == QtFatalMsg
19         || (msgType == QtWarningMsg
20             && (!qgetenv("QT_FATAL_WARNINGS").isNull())) ) {
21 
22 #if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
23         // get the current report mode
24         int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
25         _CrtSetReportMode(_CRT_ERROR, reportMode);
26 #if !defined(Q_OS_WINCE)
27         int ret = _CrtDbgReport(_CRT_ERROR, __FILE__, __LINE__, QT_VERSION_STR, buf);
28 #else
29         int ret = _CrtDbgReportW(_CRT_ERROR, _CRT_WIDE(__FILE__),
30             __LINE__, _CRT_WIDE(QT_VERSION_STR), reinterpret_cast<const wchar_t *> (QString::fromLatin1(buf).utf16()));
31 #endif
32         if (ret == 0  && reportMode & _CRTDBG_MODE_WNDW)
33             return; // ignore
34         else if (ret == 1)
35             _CrtDbgBreak();
36 #endif
37 
38 #if (defined(Q_OS_UNIX) || defined(Q_CC_MINGW))
39         abort(); // trap; generates core dump
40 #else
41         exit(1); // goodbye cruel world
42 #endif
43     }
44 }

首先是判斷用戶有沒有handler,如果有這個處理能力就讓用戶自己處理:

1 static QtMsgHandler handler = 0;                // pointer to debug handler

在Qglobal.cpp中定義。要是想自己處理,只要讓handler指向自己的處理函數就可以了,多少有點C程序的味道。

否則的話就會輸出到stderr設備上(Win系統中非WinCE的情況)。

其他,如果是FATAL(致命)錯誤或者警告,則會調用_CrtDbgReport(),其模式是_CRT_ERROR。也就是往調試器報告致命錯誤。QWarning的實現基本類似,不再深入一步一步分析。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM