• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • Visual C++中的異常處理淺析

    發表于:2007-04-27來源:作者:點擊數: 標簽:異常C++visual中的淺析
    在進入正式的講解之前,先說幾句廢話。許多的編程新手對異常處理視而不見,程序里很少考慮異常情況。一部分人甚至根本就不考慮,以為程序總是能以正確的途徑運行。譬如我們有的程序設計者調用fopen打開一個文件后,立馬就開始進行讀寫操作,根本就不考慮文件
      在進入正式的講解之前,先說幾句廢話。許多的編程新手對異常處理視而不見,程序里很少考慮異常情況。一部分人甚至根本就不考慮,以為程序總是能以正確的途徑運行。譬如我們有的程序設計者調用fopen打開一個文件后,立馬就開始進行讀寫操作,根本就不考慮文件是否正常打開了。這種習慣一定要改掉,縱使你再不愿意!這是軟件健壯性的需要!異常處理不是浪費時間!

      1.C語言異常處理

      1.1 異常終止

      標準C庫提供了abort()和exit()兩個函數,它們可以強行終止程序的運行,其聲明處于<stdlib.h>頭文件中。這兩個函數本身不能檢測異常,但在C程序發生異常后經常使用這兩個函數進行程序終止。下面的這個例子描述了exit()的行為:

    clearcase/" target="_blank" >cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    #include <stdio.h>
    #include <stdlib.h>
    int main(void)
    {
     exit(EXIT_SUCCESS);
     printf("程序不會執行到這里\n");
     return 0;
    }

      在這個例子中,main函數一開始就執行了exit函數(此函數原型為void exit(int)),因此,程序不會輸出"程序不會執行到這里"。程序中的exit(EXIT_SUCCESS)表示程序正常結束,與之對應的exit(EXIT_FAILURE)表示程序執行錯誤,只能強行終止。EXIT_SUCCESS、EXIT_FAILURE分別定義為0和1。

      對于exit函數,我們可以利用atexit函數為exit事件"掛接"另外的函數,這種"掛接"有點類似Windows編程中的"鉤子"(Hook)。譬如:

    #include <stdio.h>
    #include <stdlib.h>
    static void atExitFunc(void)
    {
     printf("atexit掛接的函數\n");
    }
    int main(void)
    {
     atexit(atExitFunc);
     exit(EXIT_SUCCESS);
     printf("程序不會執行到這里\n");
     return 0;
    }

      程序輸出"atexit掛接的函數"后即終止。來看下面的程序,我們不調用exit函數,看看atexit掛接的函數會否執行:

    #include <stdio.h>
    #include <stdlib.h>
    static void atExitFunc(void)
    {
     printf("atexit掛接的函數\n");
    }
    int main(void)
    {
     atexit(atExitFunc);
     //exit(EXIT_SUCCESS);
     printf("不調用exit函數\n");
     return 0;
    }

      程序輸出:

      不調用exit函數

      atexit掛接的函數

      這說明,即便是我們不調用exit函數,當程序本身退出時,atexit掛接的函數仍然會被執行。

      atexit可以被多次執行,并掛接多個函數,這些函數的執行順序為后掛接的先執行,例如:

    #include <stdio.h>
    #include <stdlib.h>

    static void atExitFunc1(void)
    {
     printf("atexit掛接的函數1\n");
    }

    static void atExitFunc2(void)
    {
     printf("atexit掛接的函數2\n");
    }

    static void atExitFunc3(void)
    {
     printf("atexit掛接的函數3\n");
    }

    int main(void)
    {
     atexit(atExitFunc1);
     atexit(atExitFunc2);
     atexit(atExitFunc3);
     return 0;
    }

      輸出的結果是:

       atexit掛接的函數3
       atexit掛接的函數2
       atexit掛接的函數1

      在Visual C++中,如果以abort函數(此函數不帶參數,原型為void abort(void))終止程序,則會在debug模式運行時彈出如圖1所示的對話框。


    圖1 以abort函數終止程序

      1.2 斷言(assert)

      assert宏在C語言程序的調試中發揮著重要的作用,它用于檢測不會發生的情況,表明一旦發生了這樣的情況,程序就實際上執行錯誤了,例如strcpy函數:

    char *strcpy(char *strDest, const char *strSrc)
    {
     char *address = strDest;
     assert((strDest != NULL) && (strSrc != NULL));
     while ((*strDest++ = *strSrc++) != ’\0’)
      ;
     return address;
    }

      其中包含斷言assert( (strDest != NULL) && (strSrc != NULL) ),它的意思是源和目的字符串的地址都不能為空,一旦為空,程序實際上就執行錯誤了,會引發一個abort。

      assert宏的定義為:

    #ifdef NDEBUG
    #define assert(exp) ((void)0)
    #else
    #ifdef __cplusplus
    extern "C"
    {
     #endif

     _CRTIMP void __cdecl _assert(void *, void *, unsigned);
     #ifdef __cplusplus
    }
    #endif
    #define assert(exp) (void)( (exp) || (_assert(#exp, __FILE__, __LINE__), 0) )
    #endif /* NDEBUG */

      如果程序不在debug模式下,assert宏實際上什么都不做;而在debug模式下,實際上是對_assert()函數的調用,此函數將輸出發生錯誤的文件名、代碼行、條件表達式。例如下列程序:

    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
    char * myStrcpy( char *strDest, const char *strSrc )
    {
     char *address = strDest;
     assert( (strDest != NULL) && (strSrc != NULL) );
     while( (*strDest++ = *strSrc++) != ’\0’ );
      return address;
    }
    int main(void)
    {
     myStrcpy(NULL,NULL);
     return 0;
    }

      在此程序中,為了避免我們的strcpy與C庫中的strcpy重名,將其改為myStrcpy。程序的輸出如圖2:


    圖2 assert的輸出

      失敗的斷言也會彈出如圖1所示的對話框,這是因為_assert()函數中也調用了abort()函數。

      一定要記住的是assert本質上是一個宏,而不是一個函數,因而不能把帶有副作用的表達式放入assert的"參數"中。

      1.3 errno

      errno在C程序中是一個全局變量,這個變量由C運行時庫函數設置,用戶程序需要在程序發生異常時檢測之。C運行庫中主要在math.h和stdio.h頭文件聲明的函數中使用了errno,前者用于檢測數學運算的合法性,后者用于檢測I/O操作中(主要是文件)的錯誤,例如:

    #include <errno.h>
    #include <math.h>
    #include <stdio.h>
    int main(void)
    {
     errno = 0;
     if (NULL == fopen("d:\\1.txt", "rb"))
     {
      printf("%d", errno);
     }
     else
     {
      printf("%d", errno);
     }
     return 0;
    }

      在此程序中,如果文件打開失?。╢open返回NULL),證明發生了異常。我們讀取error可以獲知錯誤的原因,如果D盤根目錄下不存在"1.txt"文件,將輸出2,表示文件不存在;在文件存在并正確打開的情況下,將執行到else語句,輸出0,證明errno沒有被設置。

      Visual C++提供了兩種版本的C運行時庫。-個版本供單線程應用程序調用,另一個版本供多線程應用程序調用。多線程運行時庫與單線程運行時庫的一個重大差別就是對于類似errno的全局變量,每個線程單獨設置了一個。因此,對于多線程的程序,我們應該使用多線程C運行時庫,才能獲得正確的error值。

      另外,在使用errno之前,我們最好將其設置為0,即執行errno = 0的賦值語句。

      1.4 其它

      除了上述異常處理方式外,在C語言中還支持非局部跳轉(使用setjmp和longjmp)、信號(使用signal、raise)、返回錯誤值或回傳錯誤值給參數等方式進行一定能力的異常處理,但是其使用不如1.1~1.3節所介紹方式常用,我們不必過細研究。

      從以上分析可知,C語言的異常處理是簡單而不全面的。與C++的異常處理比起來,C語言異常處理相形見絀,它就像娘胎里的雛嬰。

    共5頁。 1 2 3 4 5 8 :

    原文轉自:http://www.kjueaiud.com

    評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)
    ...
    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>