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.anti-gravitydesign.com

評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)
...
国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97