下面提供一些有用的提示來幫助你調試基於QT開發的應用程序。
調試配置
安裝配置qt時,要確保包含調試選項。在一些平台上,在調試模式下編譯qt將導致應用程序比預想的要大。
帶/不帶框架的調試
有關調試庫和框架的東西創建在developer.apple.com。 Apple Technical Note TN2124
在編譯Qt的時候,默認要編譯框架。在結果中,可以找到發行版和調試版(如QtCore和QtCore_debug)。如果通過-no-framework參數來編譯Qt,將為每個Qt庫編譯動態庫(如libQtCore.4.dylib和libQtCore_debug.4.dylib)。
在連接時使用框架或者不使用,將發生什么事情。目前,沒有找到令人信服的理由來確認此事。
使用框架
由於發行版和調試版的庫在框架中,應用程序自然靠框架連接。然后在調試器中運行,通過設置DYLD_IMAGE_SUFFIX來確定是運行發現版還是調試版。默認運行發行版。如果設置了DYLD_IMAGE_SUFFIX=debug,就運行調試版。
不使用框架
當通過調試配置要求qmake生成Makefile時,qmake將靠_debug版本的庫來連接,並為應用程序生成調試標示符。然后出將在GDB模式下運行,和其他平台運行GDB一樣,程序員可以跟蹤到Qt內部。
調試符號和大小
GCC生成的調試符號將占用相當大的空間。然而,通過Xcode 2.3正式版使用Dwarf符號將占用數量更小的控件。選擇-dwarf-2選項配置腳本,在配置Qt時可以激活這個功能。
默認不支持,因為之前版本的Xcode沒有和編譯器標示一起運行來實現這個功能。Mac OS X 10.5將默認設置dwarf-2符號。
dwarf-2符號包含相關源碼,因此最后的調試應用程序會比發行版編譯大一些。
Qt認識的命令行選項
在運行Qt應用程序時,需要添加幾個幫助調試的命令行選項。它們將被QApplication識別:
-nograb:應用程序不能獨占鼠標或者鍵盤。在Linux的gdb調試器中,這個選項默認生效。
-dograb:忽略任何隱式或顯示配置-nograb。即使設置了-nograb,-dograb也強制生效。
-sync:在X同步模式運行應用程序。同步模式強制X服務器首先不使用緩存立即完成每個X客戶端的請求。這將使用程序更容易調試和慢一點。這個選擇僅對X11版本的Qt有效。
警告和調試消息
Qt自帶4個向外寫警告和調試文本的方法。可以把它們使用在如下目的:
- qDebug():用於寫自定調試信息的輸出;
- qWarning():用於報告程序中的警告和可恢復的錯誤;
- qCritical():用於寫關鍵錯誤信息和報告系統錯誤;
- qFatal():用於退出前簡要地描述致命錯誤消息。
如果包含<QtDebug>頭文件,qDebug()可以當做輸出流來使用。例如:
qDebug() << "Widget" << widget << "at position" << widget->pos();
在Unix/X11 and Mac OS X平台,Qt實現了將錯誤信息輸出到stderr設備。在windows中,如果是一個控制台程序,這個信息將發送給控制台;否則就發送給調試器。你可以通過 使用qInstallMsgHandler()安裝一個消息管理者來接管那些函數。
如果設置了QT_FATAL_WARNINGS環境變量,打印完警告信息后,qWarning就退出。這讓獲取向后跟蹤更方便了。
qDebug和qWarning都是調試工具。它們都可以通過QT_NO_DEBUG_OUTPUT和QT_NO_WARNING_OUTPUT取消調試。
當程序表現得十分奇怪時,QObject::dumpObjectTree()和QObject::dumpObjectInfo()調試方法將十分有用。可以使用對象名,也可以不用。
為qDebug()提供流操作符號
你可以通過qDebug()為你的類實現流操作符號。這個類實現的流是QDebug。在QDebug中你需要知道的方法是space()和nospace()。它們都返回一個debug流;它們之間的區別是十分在每條記錄中插入一個空格。如下是一個描繪2D坐標的類的例子:
QDebug operator<<(QDebug dbg, const Coordinate &c) { dbg.nospace() << "(" << c.x() << ", " << c.y() << ")"; return dbg.space(); }
在Creating Custom Qt Types 文檔中,用源對象系統集成自定義類型被掩蓋地更深。
調試宏
頭文件QtGlobal包含一些宏定義和預定義。
3個重要的宏定義:
Q_ASSERT(cond):cond是一個布爾表達式,如果cond是false,寫警告信息:ASSERT:'cond' in file xyz.cpp,line 234,並退出。
Q_ASSERT_X(cond, where, what):cond是一個布爾表達式,where是位置,what是消息,如果cond是false,寫警告信息:ASSERT failure in where: 'what', file xyz.cpp, line 234,並退出。
Q_CHECK_PTR(ptr):ptr是一個指針。如果ptr是0,就寫警告信息:In file xyz.cpp, line 234: Out of memory,並退出。
這些宏對診斷程序錯誤非常有用。例如:
char *alloc(int size) { Q_ASSERT(size > 0); char *ptr = new char[size]; Q_CHECK_PTR(ptr); return ptr; }
如果編譯過程中定義了QT_NO_DEBUG,Q_ASSERT(), Q_ASSERT_X(), and Q_CHECK_PTR()將什么也沒有。基於這個原因,宏的參數不應該帶有副加功能。下面是一個使用Q_CHECK_PTR不正確的例子:
char *alloc(int size) { char *ptr; Q_CHECK_PTR(ptr = new char[size]); // WRONG return ptr; }
如果這段代碼通過定義QT_NO_DEBUG來編譯,Q_CHECK_PTR中的表達式將不被執行,alloc將返回一個未初始化的指針。
Qt庫包含成百個錯誤檢查。當程序錯誤發生時,它將被打印出來。因此,我們建議你在開發基於Qt的軟件時,使用Qt的調試版本。
常見問題(bugs)
有個常見的錯誤需要在這里提到的是:如果在類定義中包含Q_OBJECT宏和運行源對象編譯器(moc),但是忘記將moc生成的源代碼連接到你要執行的對象代碼中,你將得到混亂不堪的錯誤消息。任何與vtbl, _vtbl, __vtbl或者相關的錯誤都是由這個問題導致的。
參考: