Qt try catch排錯歷程——C++的異常對除零不起作用


   前幾天從網上下載了一份網友用Qt寫的作品,打開時發現它是用VS2010寫的,而我機器上只有VS2008,倒騰了半天最終沒能用VS2008打開,而自己又不想再安裝VS2010。還好在工程中有.pro文件,我只好用QtCreator打開了它。但是在編譯的時候出現了這個錯誤提示:exception handling disabled, use -fexceptions to enable,因此也就有了以下的排錯經歷。
    為了找到問題的根源,我在兩個環境下專門建了一個類似的小工程TryCatchTest。
    環境一:VS2008 + Qt4.8.3-vs2008 + Qt Visual Studio Add-in1.1.10
    環境二:Qt Creator 2.6.0 + Qt4.8.3-mingw + mingw32 4.6.2
    代碼如下:

  1. #include <QCoreApplication> 
    enum Excep 

    EXCEP_ONE, 
    EXCEP_TWO 
    }; 

    void throwFun() 

      throw EXCEP_ONE; 


    int main(int argc, char *argv[]) 

      QCoreApplication a(argc, argv); 
      try 
      { 
        throwFun(); 
      } 
      catch(Excep ex) 
      { 
        if(ex == EXCEP_ONE ) 
        { 
         //ToDo.... 
        } 
      } 
    return a.exec(); 
    }


    
    在VS環境下編譯后,一點問題都沒有,甚至連警告都沒有。這說明問題出在編譯器上,而且是編譯器的配置問題。但是怎么對mingw-g++編譯器進行配置呢?於是我在網上搜了下錯誤提示信息,找到了一篇博客http://blog.csdn.net/garybook/article/details/7764200。但是很遺憾這篇博客所解決的問題並不是Qt的,而是解決安卓的NDK問題的。但其中的內容給了我一點啟發。文章中說此問題的出現是編譯器的異常捕獲被禁用了,需要在Android.mk文件中開啟。在Android.mk文件中添加:LOCAL_CPPFLAGS += -fexceptions就可以了。於是我依葫蘆畫瓢的在TryCatchTest.pro文件中添加了一行CONFIG += -fexceptions,但是錯誤依舊。
    由於在Qt Creator中僅執行qmake時是沒問題的,而且還生成了三個文件Makefile、Makefile.Debug、Makefile.Release。在Makefile.Debug和Makefile.Release文件中我找到了以下這行:
CXXFLAGS      = -O2 -Wall -Wextra -fno-exceptions -fno-rtti $(DEFINES)
那么這一行是怎么生成的,也就是說qmake.exe到底是怎么工作的呢。為了搞清楚這個疑惑,我自己編譯了qmake的源碼,並進行了一系列的跟蹤調試(編譯qmake的過程也困難重重,其又可另寫篇日志了,此處不再贅述)。
    對qmake.exe進行跟蹤調試后,終於發現了配置-fno-exceptions的地方。它是在Qt安裝目錄下的 mkspecs\features\win32\default_pre.prf文件中。這個文件中有這樣一句:
CONFIG = rtti_off exceptions_off stl_off incremental_off thread_off windows $$CONFIG
隨之又跟蹤到了mkspecs/features/win32/exceptions_off.prf文件,在這個文件中看到了這樣一句:
CONFIG  -=  exceptions。
於是我在TryCatchTest.pro文件中添加了一行 CONFIG += exceptions(也可以寫成CONFIG  -= exceptions_off)。就這樣問題完美解決了。
    其實如果細心的話,我們可以在上面提到的Makefile文件中看到default_pre.prf、exceptions_off.prf文件的蹤跡。
    以下是Makefile文件中的部分片斷:

  1. ...... 
    Makefile: ../TryCatchTest/TryCatchTest.pro 
    ../../Qt/4.8.3/mkspecs/win32-g++/qmake.conf \ 
    ../../Qt/4.8.3/mkspecs/features/device_config.prf \ 
    ../../Qt/4.8.3/mkspecs/features/qt_functions.prf \ 
    ../../Qt/4.8.3/mkspecs/features/qt_config.prf \ 
    ../../Qt/4.8.3/mkspecs/features/exclusive_builds.prf \ 
    ../../Qt/4.8.3/mkspecs/features/default_pre.prf \ 
    ../../Qt/4.8.3/mkspecs/features/win32/default_pre.prf \ 
    ../../Qt/4.8.3/mkspecs/features/debug.prf \ 
    ../../Qt/4.8.3/mkspecs/features/debug_and_release.prf \ 
    ../../Qt/4.8.3/mkspecs/features/default_post.prf \ 
    ../../Qt/4.8.3/mkspecs/features/win32/default_post.prf \ 
    ../../Qt/4.8.3/mkspecs/features/win32/console.prf \ 
    ../../Qt/4.8.3/mkspecs/features/declarative_debug.prf \ 
    ../../Qt/4.8.3/mkspecs/features/warn_on.prf \ 
    ../../Qt/4.8.3/mkspecs/features/qt.prf \ 
    ../../Qt/4.8.3/mkspecs/features/win32/thread.prf \ 
    ../../Qt/4.8.3/mkspecs/features/moc.prf \ 
    ../../Qt/4.8.3/mkspecs/features/win32/stl_off.prf \ 
    ../../Qt/4.8.3/mkspecs/features/win32/exceptions_off.prf \ 
    ../../Qt/4.8.3/mkspecs/features/win32/rtti_off.prf \ 
    ../../Qt/4.8.3/mkspecs/features/resources.prf \ 
    ../../Qt/4.8.3/mkspecs/features/uic.prf \ 
    ../../Qt/4.8.3/mkspecs/features/include_source_dir.prf 
    ......



    從上面的片斷可以看出,編譯器的配置信息都是在features文件夾中的xxx.prf中,其實如果再仔細點的話就會發現Qt Creator啟動qmake時傳了兩個特殊的參數,-spec和win32-g++。下面是Qt Creator在編譯信息顯示框中啟動qmake的完整命令:

  1. "C:\Qt\4.8.3\bin\qmake.exe" E:\QtWork\TryCatchTest\TryCatchTest.pro -r -spec win32-g++ "CONFIG+=debug" "CONFIG+=declarative_debug"



    這兩個特殊參數的玄機我就不多說了。

    后記:
    寫這篇日志的目的主要在於記錄這個過程,對於我這種新手文筆比不了那些博客大牛,所涉及的技術知識也許在高手眼里就根本不值得一提。但是在解決這個問題的過程中使我多少了解了些qmake的機制,這無疑是一種收獲一種提升!

http://www.qtcn.org/bbs/apps.php?q=diary&a=detail&did=1197&uid=123665

-------------------------------------------------------------------------------------------------

但是感覺C++的異常對除零不起作用,比如:

#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>

enum Excep
{
EXCEP_ONE,
EXCEP_TWO
};

void throwFun()
{
  throw EXCEP_TWO;
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    try
    {
      //throwFun();
    }
    catch(Excep ex)
    {
        if(ex == EXCEP_ONE )
        {
            QMessageBox::information(NULL, "Information", QString::number(1));
        } else if(ex == EXCEP_TWO )
        {
            QMessageBox::information(NULL, "Information", QString::number(2));
        }
    }
    try {
        int i = 1;
        i = i >> 1;
        if (i==0) {
            i = 1/i;
            QMessageBox::information(NULL, "Information", QString::number(i));
        }
    }
    catch(int e)
    {
         QMessageBox::information(NULL, "Information", QString::number(e));
    }
    MainWindow w;
    w.show();

    return a.exec();
}

每次都崩潰!!

原因是C++離底層太近了,相當於直接產生了匯編引起的CPU錯誤,除非使用操作系統提供的功能(比如SEH),否則C++自身無法防止它的崩潰!這也是C++默認不開啟try catch功能的原因。


免責聲明!

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



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