Qt入門(10)——除錯技術

尹成發表於2014-09-30

命令列引數
當你執行Qt程式時,你可以指定幾個命令列引數來幫助你除錯。
-nograb 應用程式不再捕獲滑鼠或者鍵盤。當程式在Linux下執行在gdb偵錯程式中時這個選項是預設的。
-dograb 忽略任何隱含的或明顯得-nograb。即使-nograb出現在命令列的最後,-dograb也會超過-nograb生效的。
-sync 在X同步模式下執行應用程式。同步模式強迫X伺服器立即執行每一個X客戶端的請求,而並不能使用快取優化。它使得程式更加容易測試並且通常會更慢。-sync模式只對X11版本的Qt有效。
警告和除錯訊息

Qt包含了三個全域性函式來寫出警告和除錯文字。
qDebug()用來為測試及其它寫除錯輸出。
qWarning()用來在程式發生錯誤時寫警告輸出。
qFatal()用來寫致命錯誤訊息並且退出。
這些函式的Qt實現是在Unix/X11下把文字列印到標準錯誤(stderr)輸出,在Windows下會列印到偵錯程式。你可以通過安裝一個訊息處理器,qInstallMsgHandler()來接收這些函式。

當應用程式看起來或者用起來很奇怪的時候,除錯函式QObject::dumpObjectTree()和QObject::dumpObjectInfo()很有用。如果你使用了物件名稱,這將會更有用,但通常情況下是沒有名稱的。

除錯巨集
qglobal.h標頭檔案包含了很多除錯巨集和#defines。

兩個重要的巨集是:
Q_ASSERT(b)裡面的b是一個布林表示式,當b是FALSE的時候,寫出警告資訊:“ASSERT: 'b' in file file.cpp (234)”。
Q_CHECK_PTR(p)裡面的p是一個指標。如果p是空的話,寫出警告資訊:“In file file.cpp, line 234: Out of memory”。
這些巨集在檢測程式錯誤時很有用,比如像這樣:
  char *alloc( int size )
  {
      Q_ASSERT( size > 0 );
      char *p = new char[size];
      Q_CHECK_PTR( p );
      return p;
  }


如果你定義了QT_FATAL_ASSERT標記,Q_ASSERT將會呼叫fatal()而不是warning(),所以一個錯誤宣告將會導致在列印錯誤訊息後使程式退出。


注意如果QT_CHECK_STATE未定義,Q_ASSERT巨集就是一個空的表示式(參見下面)。在裡面的任何程式碼都不會被執行。相似的,如果QT_CHECK_NULL未定義,Q_CHECK_PTR也是一個空的表示式。這裡就是一個不應該如此使用Q_ASSERT和Q_CHECK_PTR的例子:
  char *alloc( int size )
  {
      char *p;
      Q_CHECK_PTR( p = new char[size] ); // WRONG
      return p;
  }




這個問題是棘手的:僅僅在正確的檢測標記被定義時,p才會被設定為健全的值。如果QT_CHECK_NULL標記沒有被定義,程式碼被編譯了,在Q_CHECK_PTR表示式中的程式碼是不會被執行的(正確地,因為它僅僅用於除錯目的)並且會分配一個瘋狂的指標。


Qt庫包含了幾百個內部檢查,當一些錯誤被檢測出時,會列印警告資訊。


Qt中的健全測試和作為結果的警告資訊是有條件的,基於不同的除錯標記的狀態:


QT_CHECK_STATE:檢測一致的/期望的物件狀態
QT_CHECK_RANGE:檢測變數範圍錯誤
QT_CHECK_NULL:檢測危險的空指標
QT_CHECK_MATH:檢測危險的數學,比如被0除
QT_NO_CHECK:關閉所有的QT_CHECK_...標記
QT_DEBUG:使除錯程式碼生效
QT_NO_DEBUG:關閉QT_DEBUG標記
預設情況下,QT_DEBUG和所有的QT_CHECK標記都是開啟的。如果要關閉QT_DEBUG,請定義QT_NO_DEBUG。如果要關閉QT_CHECK標記,請定義QT_NO_CHECK。


例項:
  void f( char *p, int i )
  {
  #if defined(QT_CHECK_NULL)
      if ( p == 0 )
          qWarning( "f: Null pointer not allowed" );
  #endif


  #if defined(QT_CHECK_RANGE)
      if ( i < 0 )
          qWarning( "f: The index cannot be negative" );
  #endif
  }




普通的Bug


這是一個如此普通的bug,所以要在這裡提到:如果你你在類生命中包含了Q_OBJECT巨集並且執行了moc,但是忘記了把moc生成的物件程式碼連線到你的可執行程式中,你就會得到非常困惑的錯誤訊息。

任何一個會提示缺乏vtbl、_vtbl、__vtbl或者和這個類似的連線錯誤都有可能是這樣的問題。

相關文章