Visual Studio中使用異常方法及開啟


  在使用Windows程序的時候,相信沒有用戶喜歡看到程序突然崩潰的情形吧!為了避免程序崩潰,程序員在編寫程序的時候最好在容易出錯的地方使用異常處理機制來保證友好的用戶體驗。特別是編寫C/C++代碼的時候,崩潰是經常的事情!
  今天一位同事給我說,編寫C/C++代碼崩潰的原因主要是因為內存操作違規。如果每次操作一塊內存或指針之前都檢查內存或指針是否有效,那么可以降低程序崩潰的次數。但是這會讓程序員很厭煩的,哈哈。所以在適當的地方加上異常處理,即使崩潰也會讓程序員更好的改善程序。當然,程序效率必然降低! 

  幸好C++規范中有異常處理機制: try catch

  但是在Visual Studio中直接使用try catch是不能產生異常的,必須手動拋出異常throw,見如下代碼:

void TryCatchfourth()
{
char* Test = NULL;
try
{
Test = new char[2];
FreeArray(Test);
throw 0; // 這里我是隨便拋出異常以測試
// 若沒有手動throw,后面即使產生異常catch里面的代碼還是不會被執行
puts("No "); // 接下來這兩句不會被執行
*(Test + 4096 ) = '\0';
}
catch (...)
{
if (NULL != Test)
{
FreeArray(Test);
}
printf("4 \n");
}
puts("Fourth");
}

  又下面這段代碼,如果將vs編譯器的選項修改:打開項目屬性→配置屬性→C/C++→代碼生成→啟用C++異常→是,但有SEH異常(/EHa) (這里編譯器默認為"是(/EHsc)")。

void TryCatchThree()
{
char* Test = NULL;
try
{
Test = new char[2];
FreeArray(Test);
*(Test + 4096 ) = '\0';
}
catch (...)
{
if (NULL != Test)
{
FreeArray(Test);
}
printf("4 \n");
}
puts("Three");
}

  修改編譯器選項之后執行TryCatchThree()就正常工作。請注意TryCatchThree()和TryCatchfourth()所采用的不同編譯選項。

  最后參考一個Windows的結構化異常處理代碼:

void TryCatchSecond()
{
char* Test = NULL;
__try
{
__try
{
Test = new char[2];
FreeArray(Test);
*(Test + 4096 ) = '\0';
// 此處數字一定要大,否則不能產生異常。
// 因為Windows平台下,new N個字節,系統分配的一定比N大。
// 4096大小剛好是一個頁面大小,如果N>4096,那就自己擴大對應數字以產生異常
}
__finally
{
if (NULL != Test)
{
FreeArray(Test);
}
printf("2 "); // this is printed second
}
}
__except ( FilterFunction(GetExceptionCode()) )
{
printf("3 \n"); // this is printed last
}
puts("Second");
}

  不管編譯器選項是否按照上述要求被修改,TryCatchSecond()均能正常工作。同事說,這是Windows結構化異常,和C++中的異常有點不一樣,我現在也不太懂,以后查到資料后在添加到博客中來。TryCatchSecond()代碼是參考MSDN中的一個例子,如下:

DWORD FilterFunction(int i = 1) 
{
printf("%d ", i); // printed first
return EXCEPTION_EXECUTE_HANDLER;
}

void TryCatchFirst()
{
char* Test = NULL;
__try
{
__try
{

// 這個API是手動設置異常代碼(這么稱呼有點別扭)
RaiseException(1, // exception code
0, // continuable exception
0, NULL); // no arguments
}
__finally
{
printf("2 "); // this is printed second
}
}
__except ( FilterFunction() )
{
printf("3 \n"); // this is printed last
}
puts("One");
}

  下面是完整代碼:(本文中代碼均在vs2008中編寫和測試,建議不要在vc6下測試,vc6對C++規范支持很不好

View Code
#include <windows.h>

// 釋放數組內存
#define FreeArray(pArray) { \
delete[] pArray; \
pArray = NULL; \
}
DWORD FilterFunction(int i = 1)
{
printf("%d ", i); // printed first
return EXCEPTION_EXECUTE_HANDLER;
}

void TryCatchFirst()
{
char* Test = NULL;
__try
{
__try
{

// 這個API是手動設置異常代碼(這么稱呼有點別扭)
RaiseException(1, // exception code
0, // continuable exception
0, NULL); // no arguments
}
__finally
{
printf("2 "); // this is printed second
}
}
__except ( FilterFunction() )
{
printf("3 \n"); // this is printed last
}
puts("One");
}

void TryCatchSecond()
{
char* Test = NULL;
__try
{
__try
{
Test = new char[2];
FreeArray(Test);
*(Test + 4096 ) = '\0';
// 此處數字一定要大,否則不能產生異常。
// 因為Windows平台下,new N個字節,系統分配的一定比N大。
// 4096大小剛好是一個頁面大小,如果N>4096,那就自己擴大對應數字以產生異常
}
__finally
{
if (NULL != Test)
{
FreeArray(Test);
}
printf("2 "); // this is printed second
}
}
__except ( FilterFunction(GetExceptionCode()) )
{
printf("3 \n"); // this is printed last
}
puts("Second");
}
void TryCatchThree()
{
char* Test = NULL;
try
{
Test = new char[2];
FreeArray(Test);
*(Test + 4096 ) = '\0';
}
catch (...)
{
if (NULL != Test)
{
FreeArray(Test);
}
printf("4 \n");
}
puts("Three");
}
void TryCatchfourth()
{
char* Test = NULL;
try
{
Test = new char[2];
FreeArray(Test);
throw 0; // 這里我是隨便拋出異常以測試
// 若沒有手動throw,后面即使產生異常catch里面的代碼還是不會被執行
puts("No "); // 接下來這兩句不會被執行
*(Test + 4096 ) = '\0';
}
catch (...)
{
if (NULL != Test)
{
FreeArray(Test);
}
printf("4 \n");
}
puts("Fourth");
}

VOID main(VOID)
{
// TryCatchFirst();
// TryCatchSecond();
// TryCatchThree();
// TryCatchfourth();
}

 

【參考資料 感謝作者】
1、我的同事 



   




 


免責聲明!

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



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