QT核心編程之調(diào)試技術(shù) (7)
QT核心編程之調(diào)試技術(shù)是本節(jié)要介紹的內(nèi)容,QT核心編程我們要分幾個(gè)部分來(lái)介紹,想?yún)⒖几鄡?nèi)容,請(qǐng)看末尾的編輯推薦進(jìn)行詳細(xì)閱讀,先來(lái)看本篇內(nèi)容。
Qt應(yīng)用程序的調(diào)試可以通過(guò)DDD進(jìn)行跟蹤調(diào)試和打印各種調(diào)試或警告信息。DDD(Data Display Debugger)是使用gdb調(diào)試工具的圖形工具,它安裝在Linux操作系統(tǒng)中,使用方法可參考DDD的幫助文檔。下面說(shuō)明如何打印各種調(diào)試或警告信息
1、命令行參數(shù)
當(dāng)你運(yùn)行Q應(yīng)用程序時(shí),你可以指定幾個(gè)命令行參數(shù)來(lái)幫助你調(diào)試。這幾個(gè)命令行參數(shù)說(shuō)明如下:
-nograb 應(yīng)用程序不再捕獲鼠標(biāo)或者鍵盤。當(dāng)程序在Linux下運(yùn)行在gdb調(diào)試器中時(shí)這個(gè)選項(xiàng)是默認(rèn)的。
-dograb 忽略任何隱含的或明顯得-nograb。即使-nograb出現(xiàn)在命令行的***,-dograb也會(huì)超過(guò)-nograb生效的。
-sync 在X同步模式下運(yùn)行應(yīng)用程序。同步模式強(qiáng)迫X服務(wù)器立即執(zhí)行每一個(gè)X客戶端的請(qǐng)求,而不使用緩存優(yōu)化。它使得程序更加容易測(cè)試并且通常會(huì)更慢。-sync模式只對(duì)X11版本的Qt有效。
2、打印警告和調(diào)試消息
Qt使用三個(gè)全局函數(shù)qDebug、qWarning和qFatal來(lái)打印警告和調(diào)試信息到標(biāo)準(zhǔn)錯(cuò)誤輸出stderr(它在缺省情況下為顯示屏,也可指定為文件)。 這三個(gè)函數(shù)說(shuō)明如下:
qDebug()用來(lái)打印調(diào)試信息,在調(diào)試版本中輸出信息,在發(fā)布版本中,函數(shù)將不起作用。
qWarning()用來(lái)在程序發(fā)生錯(cuò)誤時(shí)打印警告信息。
qFatal()用來(lái)打印致命錯(cuò)誤消息并且退出。
這些函數(shù)的Qt實(shí)現(xiàn)在Unix/X11下把文本打印到標(biāo)準(zhǔn)錯(cuò)誤輸出(stderr),在Windows下會(huì)打印到調(diào)試器。你可以通過(guò)安裝一個(gè)消息處理器,qInstallMsgHandler()來(lái)接收這些函數(shù)。
因?yàn)檫@3個(gè)函數(shù)的實(shí)現(xiàn)類似,這里只分析函數(shù)qDebug,qDebug函數(shù)的參數(shù)格式與函數(shù)printf類似,打印格式化字符串。qDebug函數(shù)列出如下(在src/tools/qglobal.cpp中):
- static QtMsgHandler handler = 0; //指向用戶定義的打印輸出函數(shù)的句柄
- static const int QT_BUFFER_LENGTH = 8196; //內(nèi)部buffer長(zhǎng)度
- void qDebug( const char *msg, ... ) //msg格式化的需要打印的字符串
- {
- char buf[QT_BUFFER_LENGTH];
- va_list ap;
- va_start( ap, msg );//使用可變的參數(shù)鏈表
- #if defined(QT_VSNPRINTF)
- QT_VSNPRINTF( buf, QT_BUFFER_LENGTH, msg, ap );
- #else vsprintf( buf, msg, ap ); //將需要打印的信息放入到buf中
- #endif va_end( ap );
- if ( handler ) { //如果用戶指定的輸出函數(shù)存在,使用它來(lái)輸出信息
- (*handler)( QtDebugMsg, buf );
- } else {
- #if defined(Q_CC_MWERKS)
- mac_default_handler(buf); //mac系統(tǒng)下的缺省輸出函數(shù)
- #elif defined(Q_OS_TEMP)
- QString fstr( buf );
- OutputDebugString( (fstr + "\n").ucs2() );
- #else fprintf( stderr, "%s\n", buf ); // 輸出到stderr#endif
- }
- }
在src/tools/qglobal.h中定義了QtMsgHandler的函數(shù)類型,并將函數(shù)qInstallMsgHandler定義為從動(dòng)態(tài)庫(kù)中輸出函數(shù)名。這兩個(gè)定義列出如下:
typedef void (*QtMsgHandler)(QtMsgType, const char *);// Q_EXPORT表示動(dòng)態(tài)庫(kù)中輸出這個(gè)函數(shù)名Q_EXPORT QtMsgHandler qInstallMsgHandler( QtMsgHandler );
函數(shù)qInstallMsgHandler被用戶用來(lái)定義一個(gè)安裝處理函數(shù),并返回以前定義的消息處理函數(shù)的指針。在一個(gè)應(yīng)用程序中只能定義一個(gè)消息處理函數(shù)?;謴?fù)以前的消息處理函數(shù)時(shí),調(diào)用qInstallMsgHandler(0)。函數(shù)列出如下(在src/tools/qglobal.cpp中):
- QtMsgHandler qInstallMsgHandler( QtMsgHandler h ){
- QtMsgHandler old = handler;
- hhandler = h;
- return old;
- }
示例:應(yīng)用qInstallMsgHandler
下面的例子說(shuō)明如果在一個(gè)應(yīng)用程序中安裝自己的程序運(yùn)行信息輸出函數(shù)。這個(gè)例子先定義了信息輸出函數(shù)myMessageOutput,然后,在程序的main函數(shù)中安裝了信息輸出函數(shù)。當(dāng)這個(gè)應(yīng)用函數(shù)運(yùn)行時(shí),就會(huì)使用函數(shù)myMessageOutput輸出運(yùn)行信息。代碼如下:
- #include <qapplication.h>
- #include <stdio.h>
- #include <stdlib.h>
- void myMessageOutput( QtMsgType type, const char *msg )//定義信息輸出函數(shù){
- switch ( type ) {
- case QtDebugMsg: //輸出調(diào)試信息
- fprintf( stderr, "Debug: %s\n", msg );
- break;
- case QtWarningMsg: //輸出警告信息
- fprintf( stderr, "Warning: %s\n", msg );
- break;
- case QtFatalMsg: //輸出致命信息
- fprintf( stderr, "Fatal: %s\n", msg );
- abort(); //中斷運(yùn)行,退出程序
- }
- }
- int main( int argc, char **argv ){
- qInstallMsgHandler( myMessageOutput ); //安裝信息輸出函數(shù)
- QApplication a( argc, argv );
- ...
- return a.exec();
- }
還有另外兩個(gè)打印對(duì)象信息的調(diào)試函數(shù)QObject::dumpObjectTree()和QObject::dumpObjectInfo()。它們只在程序調(diào)試版本下,輸出信息,在發(fā)布版本中,這兩個(gè)函數(shù)不起作用。函數(shù)QObject::dumpObjectInfo()打印一個(gè)對(duì)象信號(hào)連接等方面的信息。函數(shù)QObject::dumpObjectTree()打印出子對(duì)象樹。
3、調(diào)試宏
在程序運(yùn)行中還常使用宏Q_ASSERT和Q_CHECK_PTR來(lái)輸出信息,這兩個(gè)宏說(shuō)明如下:
(1)Q_ASSERT(b)中的b是一個(gè)布爾表達(dá)式,當(dāng)b是FALSE的時(shí)候,打印出類似的警告信息:"ASSERT:‘b’ in file file.cpp (234)"。
(2)Q_CHECK_PTR(p)中的p是一個(gè)指針。如果p是空的話,打印出類似的警告信息:"In file file.cpp, line 234: Out of memory"。
宏Q_ASSERT實(shí)質(zhì)上是調(diào)用函數(shù)qFatal或qWarning輸出信息,列出如下(在src/tools/qglobal.h中):
- #if !defined(Q_ASSERT)
- # if defined(QT_CHECK_STATE)
- # if defined(QT_FATAL_ASSERT)
- # define Q_ASSERT(x) //打印x,文件名,在程序源代碼中的行號(hào)
- # else
- # define Q_ASSERT(x)
- # endif
- # else
- # define Q_ASSERT(x)
- # endif#endif
宏Q_CHECK_PTR實(shí)質(zhì)上調(diào)用函數(shù)qWarning輸出信息,宏定義Q_CHECK_PTR列出如下(在src/tools/qglobal.h中):
- #if defined(QT_CHECK_NULL)
- # define Q_CHECK_PTR(p) (qt_check_pointer#else# define Q_CHECK_PTR(p)
- #endif Q_EXPORT bool qt_check_pointer( bool c, const char *, int );
函數(shù)qt_check_pointer實(shí)現(xiàn)信息輸出操作,函數(shù)列出如下(在src/tools/qglobal.cpp中):
- bool qt_check_pointer( bool c, const char *n, int l ){ if ( c ) qWarning( "In file %s, line %d: Out of memory", n, l );
- return TRUE;}
示例2:運(yùn)行宏Q_ASSERT和Q_ASSERT
宏Q_ASSERT和Q_ASSERT常用來(lái)檢測(cè)程序錯(cuò)誤,下面例子使用了這兩個(gè)宏:
- char *alloc( int size ){
- Q_ASSERT( size > 0 ); //如果size > 0表達(dá)式不成立,打印警告信息
- char *p = new char[size];
- Q_CHECK_PTR( p ); //如果指針p為空,打印警告信息
- return p;
- }
Qt基于不同的調(diào)試標(biāo)記打印不同類型的警告信息。Qt使用了下面的宏定義說(shuō)明了不同的調(diào)試標(biāo)記(在src/tools/qglobal.h中):
QT_CHECK_STATE:檢測(cè)一致的/期望的對(duì)象狀態(tài)
QT_CHECK_RANGE:檢測(cè)變量范圍錯(cuò)誤
QT_CHECK_NULL:檢測(cè)危險(xiǎn)的空指針
QT_CHECK_MATH:檢測(cè)危險(xiǎn)的數(shù)學(xué),比如被0除
QT_NO_CHECK:關(guān)閉所有的QT_CHECK_...標(biāo)記
QT_DEBUG:使調(diào)試代碼生效
QT_NO_DEBUG:關(guān)閉QT_DEBUG標(biāo)記
默認(rèn)情況下,QT_DEBUG和所有的QT_CHECK標(biāo)記都是打開的。如果要關(guān)閉QT_DEBUG,請(qǐng)定義QT_NO_DEBUG。如果要關(guān)閉QT_CHECK標(biāo)記,請(qǐng)定義QT_NO_CHECK。
示例3: 打印不同類型的警告信息
下面的例子根據(jù)不同的宏定義打印不同類型的警告信息。代碼如下:
- void f( char *p, int i ){
- #if defined(QT_CHECK_NULL) //檢測(cè)危險(xiǎn)的空指針
- if ( p == 0 ) qWarning( "f: Null pointer not allowed" );
- #endif #if defined(QT_CHECK_RANGE) //檢測(cè)變量范圍錯(cuò)誤
- if ( i < 0 )
- qWarning( "f: The index cannot be negative" );
- #endif}
小結(jié):QT核心編程之調(diào)試技術(shù)的內(nèi)容介紹完了,需要本文能對(duì)你有所幫助,需要更多資料的話,請(qǐng)參考編輯推薦。