韩剧1988免费观看全集_久久影视三级福利片_亚洲视频在线观看免费_在线观看欧美日韩_国产亚洲激情在线_亚洲精品美女久久久_欧美国产日韩一区二区在线观看_91在线观看免费高清完整版在线观看_日韩av免费看_国产又爽又黄的激情精品视频_琪琪亚洲精品午夜在线_欧美性猛xxx_不卡毛片在线看_国产亚洲日本欧美韩国_91国内在线视频_精品国产福利视频

當(dāng)前位置:蘿卜系統(tǒng)下載站 > 技術(shù)開發(fā)教程 > 詳細(xì)頁面

Visual C++ 中的結(jié)構(gòu)異常處理

Visual C++ 中的結(jié)構(gòu)異常處理

更新時(shí)間:2022-10-15 文章作者:未知 信息來源:網(wǎng)絡(luò) 閱讀次數(shù):

jimmy 戰(zhàn)志杰 編譯

本文編譯自Jeffrey Richter先生的“Advanced Windows”部分章節(jié)。
1、引言
在“C++中例外的處理”一文中(見計(jì)算機(jī)世界網(wǎng)2001年12月20日),我們討論了C++中的例外(或異常)處理。本文將進(jìn)一步探討Visual C++中的結(jié)構(gòu)異常處理。
想象一下,如果在編程過程中你不需要考慮任何錯(cuò)誤,你的程序永遠(yuǎn)不會(huì)出錯(cuò),有足夠的內(nèi)存,你需要的文件永遠(yuǎn)存在,這將是一件多么愉快的事。這時(shí)你的程序不需要太多的if語句轉(zhuǎn)來轉(zhuǎn)去,非常容易寫,容易讀,也容易理解。如果你認(rèn)為這樣的編程環(huán)境是一種夢(mèng)想,那么你就會(huì)喜歡結(jié)構(gòu)異常處理(structu reed exception handling)。
結(jié)構(gòu)異常處理的本質(zhì)就是讓你專心于如何去完成你的任務(wù)。如果在程序運(yùn)行過程中出現(xiàn)任何錯(cuò)誤,系統(tǒng)會(huì)接收(catch)并通知(notify)你。雖然利用結(jié)構(gòu)異常處理你不可能完全忽略你的程序出錯(cuò)的可能性,但是結(jié)構(gòu)異常處理確確實(shí)實(shí)允許你將你的主要任務(wù)與錯(cuò)誤處理分離開來。這種分離使得你可以集中精力于你的工作,而在以后在考慮可能的錯(cuò)誤。
結(jié)構(gòu)異常處理的主要工作是由編譯器來完成的,而不是由操作系統(tǒng)。編譯器在遇到例外程序段時(shí)需要產(chǎn)生額外的特殊代碼來支持結(jié)構(gòu)異常處理。所以,每一個(gè)編譯器產(chǎn)品供應(yīng)商可能使用自己的語法和規(guī)定。這里我們采用微軟的Visual C++編譯器來進(jìn)行討論。
注意不要將這里討論的結(jié)構(gòu)異常處理與C++中的異常處理混為一談。C++中的異常處理是另一種形式的異常處理,它使用了C++的關(guān)鍵詞catch和throw。
微軟最早在Visual C++版本2.0引進(jìn)結(jié)構(gòu)異常處理。結(jié)構(gòu)異常處理主要由兩部分組成:中斷處理(termination handling)和例外處理(exception handling)。
2、中斷處理句柄(termination handler)
2.1、中斷處理句柄定義
中斷處理句柄保證了,不論進(jìn)程如何離開另一程序段--這里稱之為守衛(wèi)體(guarded body),該句柄內(nèi)的程序段永遠(yuǎn)會(huì)被調(diào)用和執(zhí)行。微軟的Visual C++編譯器的中斷處理句柄語法為
__try {
// Guarded body
.
.
.
}
__finally {
// Termination handler
.
.
.
}
這里的__try和__finally勾畫出了中斷處理句柄的兩個(gè)部分。在上面的例子中,操作系統(tǒng)和編譯器一起保證了不論包含在__try內(nèi)的程序段出現(xiàn)何種情況,包含在__finally內(nèi)的程序段永遠(yuǎn)會(huì)被運(yùn)行。不論你在__try內(nèi)的程序段中調(diào)用return、goto或longjump,__finally內(nèi)的中斷處理句柄永遠(yuǎn)會(huì)被調(diào)用。其流程為
// 1、執(zhí)行try程序段前的代碼
__try {
// 2、執(zhí)行try程序段內(nèi)的代碼
}
__finally {
// 3、執(zhí)行finally程序段內(nèi)的代碼
}
// 4、執(zhí)行finally程序段后的代碼
2.2、幾個(gè)例子
下面我們通過幾個(gè)具體例子來討論中斷處理句柄是如何工作的。
2.2.1、例1--Funcenstein1
清單一給出了我們的第一個(gè)例子。
DWORD Funcenstein1(void) {
DWORD dwTemp;
// 1. Do any processing here.
.
.
.
__try {
// 2. request permission to access protected data, and then use it.
WaitForSingleObject(g_hSem, INFINITE);
g_dwProtectedData = 5;
dwTemp = g_dwProtectedData;

__finally {
// 3. Allow others to use protected data.
ReleaseSemaphore(g_hSem, 1, NULL);

// 4. Continue processing.
return (dwTemp);

例1 Funcenstein1函數(shù)代碼
在函數(shù)Funcenstein1中,我們使用了try-finally程序塊。但是它們并沒有為我們做多少工作:等待一個(gè)指示燈信號(hào),改變保護(hù)數(shù)據(jù)的內(nèi)容,將新的數(shù)據(jù)指定給一個(gè)局域變量dwTemp,釋放指示燈信號(hào),返回新的數(shù)據(jù)給調(diào)用函數(shù)。
2.2.2、例2--Funcenstein2
現(xiàn)在讓我們對(duì)Funcenstein1稍稍做一些改動(dòng),看看會(huì)出現(xiàn)什么情況(見清單二)。
DWORD Funcenstein2(void) {
DWORD dwTemp;
// 1. Do any processing here.
.
.
.
__try {
// 2. request permission to access protected data, and then use it.
WaitForSingleObject(g_hSem, INFINITE);
g_dwProtectedData = 5;
dwTemp = g_dwProtectedData;
// Return the new value.
return (dwTemp);

__finally {
// 3. Allow others to use protected data.
ReleaseSemaphore(g_hSem, 1, NULL);

// 4. Continue processing--this code will never execute in this version.
dwTemp = 9;
return (dwTemp);

例2 Funcenstein2函數(shù)代碼
在函數(shù)Funcenstein2中,我們?cè)趖ry程序段里加入了一個(gè)return返回語句。該返回語句告訴編譯器,你想離開函數(shù)Funcenstein2并返回dwTemp內(nèi)的內(nèi)容5給調(diào)用函數(shù)。然而,如果此返回語句被執(zhí)行,本線程永遠(yuǎn)不會(huì)釋放指示燈信號(hào),其它線程也就永遠(yuǎn)不會(huì)得到該指示燈信號(hào)。你可以想象,在多線程程序中這是一個(gè)多么嚴(yán)重的問題。
但是,使用了中斷處理句柄避免了這種情況發(fā)生。當(dāng)返回語句試圖離開try程序段時(shí),編譯器保證了在finally程序段內(nèi)的代碼得到執(zhí)行。所以,finally程序段內(nèi)的代碼保證會(huì)在try程序段中的返回語句前執(zhí)行。在函數(shù)Funcenstein2中,將調(diào)用ReleaseSemaphore放在finally程序段內(nèi)保證了指示燈信號(hào)會(huì)得到釋放。
在finally程序段內(nèi)的代碼被執(zhí)行后,函數(shù)Funcenstein2立即返回。這樣,因?yàn)閠ry程序段內(nèi)的return返回語句,任何finally程序段后的代碼都不會(huì)被執(zhí)行。因而Funcenstein2返回值是5,而不是9。
必須指出的是,當(dāng)遇到例2中這種過早返回語句時(shí),編譯器需要產(chǎn)生額外的代碼以保證finally程序段內(nèi)的代碼的執(zhí)行。此過程稱作為局域展開。當(dāng)然,這必然會(huì)降低整個(gè)程序的效率。所以,你應(yīng)該盡量避免使用這類代碼。在后面我們會(huì)討論關(guān)鍵詞__leave,它可以幫助我們避免編寫出現(xiàn)局域展開一類的代碼。
2.2.3、例3--Funcenstein3
現(xiàn)在讓我們對(duì)Funcenstein2做進(jìn)一步改動(dòng),看看會(huì)出現(xiàn)什么情況(見例3)。
DWORD Funcenstein3(void) {
DWORD dwTemp;
// 1. Do any processing here.
.
.
.
__try {
// 2. request permission to access protected data, and then use it.
WaitForSingleObject(g_hSem, INFINITE);
g_dwProtectedData = 5;
dwTemp = g_dwProtectedData;
// Try to jump over the finally block.
goto ReturnValue;

__finally {
// 3. Allow others to use protected data.
ReleaseSemaphore(g_hSem, 1, NULL);

dwTemp = 9;
// 4. Continue processing.
ReturnValue:
return (dwTemp);

例3 Funcenstein3函數(shù)代碼
在函數(shù)Funcenstein3中,當(dāng)遇到goto語句時(shí)編譯器會(huì)產(chǎn)生額外的代碼以保證finally程序段內(nèi)的代碼得到執(zhí)行。但是,這一次finally程序段后ReturnValue標(biāo)簽后面的代碼會(huì)被執(zhí)行,因?yàn)閠ry或finally程序段內(nèi)沒有返回語句。函數(shù)的返回值是5。同樣,由于goto語句打斷了從try程序段到finally程序段的自然流程,程序的效率會(huì)降低。
2.2.4、例4--Funcfurter1
現(xiàn)在讓我們來看中斷處理真正展現(xiàn)其功能的一個(gè)例子。(見例4)。
DWORD Funcfurter1(void) {
DWORD dwTemp;
// 1. Do any processing here.
.
.
.
__try {
// 2. request permission to access protected data, and then use it.
WaitForSingleObject(g_hSem, INFINITE);
dwTemp = Funcinator(g_dwProtectedData);

__finally {
// 3. Allow others to use protected data.
ReleaseSemaphore(g_hSem, 1, NULL);

// 4. Continue processing.
return (dwTemp);

例4 Funcfurter1函數(shù)代碼
設(shè)想try程序段內(nèi)調(diào)用的Funcinator函數(shù)具有某種缺陷而造成無效內(nèi)存讀寫。在16位視窗應(yīng)用程序中,這會(huì)導(dǎo)致一個(gè)已定義好的錯(cuò)誤信息對(duì)話框出現(xiàn)。在用戶關(guān)閉對(duì)話框的同時(shí)該應(yīng)用程序也終止運(yùn)行。在不具有try-finally的Win32應(yīng)用程序中,這會(huì)導(dǎo)致程序終止運(yùn)行,指示燈信號(hào)永遠(yuǎn)不會(huì)得到釋放。這就造成了等待該指示燈信號(hào)的其它線程會(huì)永遠(yuǎn)等待下去。而將ReleaseSemaphore放在finally程序段內(nèi)則從根本上保證了不論何種情況出現(xiàn)指示燈信號(hào)都會(huì)得到釋放。
如果中斷處理句柄能夠處理由于無效內(nèi)存讀寫而造成的程序中斷,我們就完全有理由相信它能夠處理諸如setjump/longjump、break和continue這類的中斷轉(zhuǎn)移。事實(shí)也正是這樣。
2.3、小測(cè)試
下面一個(gè)例子(見清單五)請(qǐng)讀者猜測(cè)一下函數(shù)FuncaDoodleDoo的返回值。(答案為14)
DWORD FuncaDoodleDoo(void) {
DWORD dwTemp = 0;
while (dwTemp 〈 10) {
__try {
if (dwTemp == 2)
continue;
if (dwTemp == 3)
break;

__finally {
dwTemp++;

dwTemp++;
}
dwTemp += 10;
return (dwTemp);

FuncaDoodleDoo函數(shù)代碼
雖然中斷處理句柄能夠接收出現(xiàn)在try程序段內(nèi)的絕大部分異常情況,但是如果線程或進(jìn)程中斷執(zhí)行的話,則finally程序段內(nèi)的代碼不會(huì)被執(zhí)行。調(diào)用ExitThread或ExitProcess就會(huì)立即造成線程或進(jìn)程的中斷,而不會(huì)執(zhí)行finally程序段。另外,如果其它的應(yīng)用程序調(diào)用ExitThread或ExitProcess而造成你的線程或進(jìn)程中斷,你程序中的finally程序段也不會(huì)被執(zhí)行。一些C函數(shù)如abort會(huì)調(diào)用ExitProcess,也會(huì)導(dǎo)致你的finally程序段不被執(zhí)行。對(duì)此你無能為力。但你可以防止你自己提早調(diào)用ExitThread或ExitProcess。
2.4、應(yīng)用例子
我們已經(jīng)討論了中斷處理句柄的句法及語法。現(xiàn)在我們進(jìn)一步討論如何利用中斷處理句柄來簡化一個(gè)比較復(fù)雜的編程問題。
首先讓我們來看一個(gè)沒有使用中斷處理句柄的例子,程序源代碼見例6。
BOOL Funcarama1 (void) {
HANDLE hFile = INVALID_HANDLE_VALUE;
LPVOID lpBuf = NULL;
DWORD dwNumBytesRead;
BOOL fOk;
hFile = CreateFile("SOMEDATA.DAT", GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
return (FALSE);
}
lpBuf = VitualAlloc(NULL, 1024, MEM_COMMIT, PAGE_READWRITE);
if (lpBuf == NULL) {
CloseHandle(hFile);
return (FALSE);
}
fOk = ReadFile(hFile, lpBuf, 1024, &dwNumBytesRead, NULL);
if (!fOk || (dwNumBytesRead == 0)) {
VirtualFree(lpBuf, MEM_RELEASE | MEM_DECOMMIT);
CloseHandle(hFile);
return (FALSE);
}
// Do some calculation on the data.
.
.
.

// Clean up all the resources.
VirtualFree(lpBuf, MEM_RELEASE | MEM_DECOMMIT);
CloseHandle(hFile);
return (TRUE);
}
例6 沒有使用中斷處理句柄的Funcarama1函數(shù)代碼
在上例Funcarama1函數(shù)中,所有的錯(cuò)誤診斷使得該函數(shù)難以理解、維護(hù)和修改。當(dāng)然,我們可以對(duì)Funcarama1函數(shù)進(jìn)行一些改動(dòng),使其易于理解(見例7)。
BOOL Funcarama2 (void) {
HANDLE hFile = INVALID_HANDLE_VALUE;
LPVOID lpBuf = NULL;
DWORD dwNumBytesRead;
BOOL fOk, fSuccess = FALSE;
hFile = CreateFile("SOMEDATA.DAT", GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
lpBuf = VitualAlloc(NULL, 1024, MEM_COMMIT, PAGE_READWRITE);
if (lpBuf != NULL) {
fOk = ReadFile(hFile, lpBuf, 1024, &dwNumBytesRead, NULL);
if (fOk || (dwNumBytesRead != 0)) {
// Do some calculation on the data.
.
.
.
fSuccess = TRUE;
}
}
VirtualFree(lpBuf, MEM_RELEASE | MEM_DECOMMIT);
}
CloseHandle(hFile);
return (fSuccess);
}
例7 沒有使用中斷處理句柄的Funcarama2函數(shù)代碼
雖然函數(shù)Funcarama2容易理解,但是仍然難于維護(hù)和修改。
現(xiàn)在讓我們來利用中斷處理句柄重寫Funcaram1函數(shù),其代碼如清單八。
BOOL Funcarama3 (void) {
HANDLE hFile = INVALID_HANDLE_VALUE;
LPVOID lpBuf = NULL;
__try {
DWORD dwNumBytesRead;
BOOL fOk;
hFile = CreateFile("SOMEDATA.DAT", GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
return (FALSE);
}
lpBuf = VitualAlloc(NULL, 1024, MEM_COMMIT, PAGE_READWRITE);
if (lpBuf == NULL) {
return (FALSE);
}
fOk = ReadFile(hFile, lpBuf, 1024, &dwNumBytesRead, NULL);
if (!fOk || (dwNumBytesRead == 0)) {
VirtualFree(lpBuf, MEM_RELEASE | MEM_DECOMMIT);
return (FALSE);
}
// Do some calculation on the data.
.
.
.

__finally {
// Clean up all the resources.
if (lpBuf != NULL)
VirtualFree(lpBuf, MEM_RELEASE | MEM_DECOMMIT);
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
}
// Continue processing.
return (TRUE);
}
例8 使用了中斷處理句柄的Funcarama3函數(shù)代碼
Funcarama3函數(shù)版的好處是所有的清除工作都集中在一個(gè)地方:finally程序段內(nèi)。這樣在我們需要對(duì)該函數(shù)增加新的條件語句時(shí),我們只需要在finally程序段內(nèi)簡單增添一行清除語句就可以了,而不必回過頭來在每一出可能出錯(cuò)的地方添加清除語句。
Funcarama3函數(shù)的真正問題在于其效率。我們以前說過應(yīng)盡可能的避免在try程序段內(nèi)使用return語句。為了避免這種情況,微軟在它的編譯器里引進(jìn)了另一個(gè)關(guān)鍵詞__leave。利用關(guān)鍵詞__leave重寫的Funcarama3函數(shù)見例9。
BOOL Funcarama4 (void) {
HANDLE hFile = INVALID_HANDLE_VALUE;
LPVOID lpBuf = NULL;
// Assume that the function will not execute successfully.
BOOL fFunctionOk = FALSE;
__try {
DWORD dwNumBytesRead;
BOOL fOk;
hFile = CreateFile("SOMEDATA.DAT", GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
__leave;
}
lpBuf = VitualAlloc(NULL, 1024, MEM_COMMIT, PAGE_READWRITE);
if (lpBuf == NULL) {
__leave;
}
fOk = ReadFile(hFile, lpBuf, 1024, &dwNumBytesRead, NULL);
if (!fOk || (dwNumBytesRead == 0)) {
VirtualFree(lpBuf, MEM_RELEASE | MEM_DECOMMIT);
__leave;
}
// Do some calculation on the data.
.
.
.
// Indicate that the entire function executed successfully.
fFunctionOk = TRUE;

__finally {
// Clean up all the resources.
if (lpBuf != NULL)
VirtualFree(lpBuf, MEM_RELEASE | MEM_DECOMMIT);
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
}
// Continue processing.
return (fFunctionOk);
}
例9 使用了中斷處理句柄和關(guān)鍵詞__leave的Funcarama4函數(shù)代碼
try程序段內(nèi)的關(guān)鍵詞__leave導(dǎo)致程序運(yùn)行指針直接跳到try程序段的結(jié)尾(你可以將此看成為跳到try程序段的結(jié)束花括弧)。這樣,因?yàn)榭刂屏鞒虒ⅰ白匀弧钡碾x開try程序段,進(jìn)入finally程序段,所以不需付出額外代價(jià)而導(dǎo)致效率降低。但是你需要引進(jìn)一個(gè)新的變量來指示整個(gè)函數(shù)的運(yùn)行是否成功。
從try程序段到finally程序段,控制流程既可以是自然進(jìn)入,也可以是由于異常的出現(xiàn)而導(dǎo)致控制流程過早離開try程序段而進(jìn)入finally程序段。為確定何種情況下造成finally程序段的運(yùn)行,我們可以調(diào)用AbnormalTermination函數(shù)來診斷。
BOOL AbnormalTermination(VOID);
該函數(shù)只能在finally程序段內(nèi)調(diào)用以診斷與此finally相對(duì)應(yīng)的try程序段是否是過早離開。如果AbnormalTermination的返回值是FALSE,表明程序流程是自然離開try程序段。否則,則是過早離開。
3、異常處理句柄(Exception handler)
3.1、異常(或例外)處理句柄的定義
異常(或例外)是你不希望出現(xiàn)的事件。在一個(gè)完好的應(yīng)用程序中,你不希望讀寫無效內(nèi)存地址或除數(shù)為零的情況出現(xiàn)。但是這類錯(cuò)誤的確會(huì)發(fā)生。在出現(xiàn)這類錯(cuò)誤時(shí),CPU會(huì)負(fù)責(zé)提出針對(duì)該類錯(cuò)誤的例外。當(dāng)CPU提出一個(gè)例外時(shí),我們稱之為硬件異常(或例外)(hardware exception)。操作系統(tǒng)和應(yīng)用程序自身也可以提出自己的異常。這類異常我們稱之為軟件異常(或例外)(software exception)。
當(dāng)一個(gè)硬件異;蜍浖惓1惶岢鰰r(shí),操作系統(tǒng)向你的程序提供一種機(jī)會(huì)使得你的程序可以診斷那類異常被提出并允許你的程序?qū)Υ诉M(jìn)行處理。異常處理句柄的語法為
__try {
// Guarded body
.
.
.
}
__except (exception filter) {
// Exception handler
.
.
.
}
請(qǐng)注意關(guān)鍵詞__except。當(dāng)你建立一個(gè)try程序段時(shí),它必須跟隨一個(gè)finally程序段或一個(gè)except程序段。一個(gè)try程序段不能同時(shí)既跟隨一個(gè)finally程序段又跟隨一個(gè)except程序段。一個(gè)try程序段也不能同時(shí)跟隨多個(gè)finally程序段或多個(gè)except程序段。但是,try-finally程序段卻可以嵌套在try-except程序段內(nèi),或try-except程序段嵌套在try-finally程序段內(nèi)。
3.2、幾個(gè)例子
不同于中斷處理句柄,異常處理句柄直接由操作系統(tǒng)執(zhí)行,編譯器不需要做太多工作。下面我們通過幾個(gè)具體例子來討論異常處理句柄是如何工作的。
3.2.1、例5--Funcmeister1函數(shù)
下面是一個(gè)使用了try-except異常處理句柄的函數(shù)Funcmeister1,其代碼見清單十。
DWORD Funcmeister1 (void) {
DWORD dwTemp;
// 1. Do any processing here.
.
.
.
__try {
// 2. Perform some operation.
dwTemp = 0;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
// 3. Handle an exception; this never executes.
.
.
.
}
// 3. Continue processing.
return (dwTemp);
}
例10 例5Funcmeister1函數(shù)代碼
在Funcmeister1函數(shù)中的try程序段內(nèi),我們簡單地將dwTemp賦值為零。該操作不會(huì)導(dǎo)致任何異常的提出。所以,except程序段內(nèi)的程序永遠(yuǎn)不會(huì)被執(zhí)行。請(qǐng)注意,這有別于中斷處理句柄try-finally。在執(zhí)行了dwTemp賦值語句后的下一個(gè)執(zhí)行語句是return返回語句。
雖然我們不鼓勵(lì)在try程序段內(nèi)使用return, goto, continue和break語句,但是在異常處理句柄的try程序段內(nèi)使用這些語句不會(huì)象中斷處理句柄那樣造成運(yùn)行代碼的增加和效率下降。
3.2.2、例6--Funcmeister2函數(shù)
讓我們對(duì)Funcmeister1函數(shù)進(jìn)行一些改動(dòng),看看會(huì)出現(xiàn)什么情況。改動(dòng)后的函數(shù)見例11。
DWORD Funcmeister2 (void) {
DWORD dwTemp = 0;
// 1. Do any processing here.
.
.
.
__try {
// 2. Perform some operation(s).
dwTemp = 5 / dwTemp; // Generate an exception
dwTemp += 10; // Never excutes
}
__except ( /* 3. Evaluate filter. */ EXCEPTION_EXECUTE_HANDLER) {
// 4. Handle an exception; this never executes.
MessageBeep(0);
.
.
.
}

// 5. Continue processing.
return (dwTemp);
}
例11 例6Funcmeister2函數(shù)代碼
函數(shù)Funcmeister2中的try程序段dwTemp = 5 / dwTemp語句導(dǎo)致CPU提出一個(gè)硬件異常。當(dāng)該異常被提出時(shí),操作系統(tǒng)會(huì)尋找相對(duì)應(yīng)的except程序段的起始位置并評(píng)估其異常篩選表達(dá)式(exception filter expression)。異常篩選表達(dá)式可以取下列標(biāo)識(shí)符值之一。這些標(biāo)識(shí)符定義在Win32 EXCPT.H頭文件中。
標(biāo)識(shí)符 定義為
EXCEPTION_EXECUTE_HANDLER 1
EXCEPTION_CONTINUE_SEARCH 0
EXCEPTION_CONTINUE_EXECUTION -1
3.3、異常篩選(exception filter)
EXCEPTION_EXECUTE_HANDLER表明當(dāng)一個(gè)異常出現(xiàn)時(shí),運(yùn)行程序跳到except程序段轉(zhuǎn)而執(zhí)行except程序段內(nèi)的代碼。except程序段內(nèi)的代碼執(zhí)行完后,系統(tǒng)認(rèn)為該異常已處理完,接著繼續(xù)執(zhí)行except程序段后的代碼。
EXCEPTION_CONTINUE_EXECUTION表明當(dāng)一個(gè)異常出現(xiàn)時(shí),運(yùn)行程序不立即執(zhí)行except程序段內(nèi)的代碼而返回try程序段內(nèi)產(chǎn)生異常的語句繼續(xù)執(zhí)行該語句。
EXCEPTION_CONTINUE_SEARCH表明當(dāng)一個(gè)異常出現(xiàn)時(shí),運(yùn)行程序不執(zhí)行該except程序段內(nèi)的代碼而尋求由高一級(jí)的異常處理句柄來處理此異常。
Win32 WINBASE.H頭文件中定義了可能出現(xiàn)的各種異常代碼。我們可以通過調(diào)用GetExceptionCode函數(shù)來診斷何種異常被提出,從而決定異常處理句柄該采取何種行動(dòng)。GetExceptionCode函數(shù)定義為
DWORD GetExceptionCode(VOID);
它的返回值表明何種異常出現(xiàn)。下面的程序說明如何調(diào)用GetExceptionCode函數(shù)。
__try {
x = 0;
y = 4 / x;
}
__except ((GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO) ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Handle divide by zero exception.
}
當(dāng)一個(gè)異常發(fā)生時(shí),操作系統(tǒng)會(huì)將有關(guān)該異常的信息儲(chǔ)存在三個(gè)結(jié)構(gòu)中,并將它們存放在提出此異常線程的堆棧里。這三個(gè)結(jié)構(gòu)是EXCEPTION_RECORD,CONTEXT,和EXCEPTION_POINTERS。EXCEPTION_RECORD儲(chǔ)存著與CPU無關(guān)的異常信息,CONTEXT則儲(chǔ)存著與CPU有關(guān)的異常信息。EXCEPTION_POINTERS結(jié)構(gòu)包含了兩個(gè)分別指向EXCEPTION_RECORD和CONTEXT的指針。
typedef struct _EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
} EXCEPTION_POINTERS
假如你的程序需要這些異常信息,你可以通過調(diào)用GetExceptionInformation函數(shù)來獲取。
LPEXCEPTION GetExceptionInformation(void);
GetExceptionInformation函數(shù)返回一個(gè)指向EXCEPTION_POINTERS結(jié)構(gòu)的指針。下面的函數(shù)說明了如何調(diào)用GetExceptionInformation函數(shù)。
void FuncSkunk (void) {
// Declare variables that we can use to save the exception
// record and the context if an exception should occur.
EXCEPTION_RECORD SavedExceptRec;
CONTEXT SavedContext;
.
.
.
__try {
.
.
.
}
__except (
SavedExceptRec =
*(GetExceptionInformation())->ExceptionRecord,
SavedContext =
*(GetExceptionInformation())->ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
// We can use the SavedExceptRec and SavedContext
// variables inside the handler code block.
switch (SavedExceptRec.ExceptionCode) {
.
.
.
}
}
.
.
.
}
注意,在上面的異常篩選表達(dá)式程序中我們使用了C語言的“,”操作符。許多程序員對(duì)此并不是很熟悉。該操作符告訴編譯器從左到右運(yùn)行由“,”分離的各表達(dá)式。在所有的表達(dá)式都運(yùn)行完后,返回最后一個(gè)(或最右面的)表達(dá)式的值。
4、軟件異常(software exception)
至此為止我們所討論的是如何處理由CPU提出的硬件異常(hardware exception)。通常,操作系統(tǒng)或應(yīng)用程序自身提出的軟件異常也非常有用。例如,HeapAlloc函數(shù)就提供了一個(gè)非常好的利用軟件異常的例子。在調(diào)用HeapAlloc時(shí),你可以設(shè)置HEAP_GENERATE-EXCEPTIONS指示旗(flag)。這樣如果HeapAlloc不能滿足你的內(nèi)存分配要求,它會(huì)產(chǎn)生一個(gè)STATUS_NO_MEMORY軟件異常。
假如你想利用這個(gè)異常,你可以在你的try程序段內(nèi)繼續(xù)編寫你的代碼,如同內(nèi)存分配總是會(huì)成功一樣。如果內(nèi)存分配失敗,你可以利用except程序段來處理這個(gè)異;蚶胒inally程序段來做清除工作。
你的程序不需要知道你要處理的異常是軟件異常還是硬件異常。你利用try-finally和try-except來處理軟件異常和硬件異常的方式是一樣的。但是你可以讓你的程序象HeapAlloc函數(shù)一樣提出自己的異常。為了在你的程序中提出軟件異常,你需要調(diào)用RaiseException函數(shù)。
VOID RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags,
DWORD cArguments, LPDWORD lpArguments);
關(guān)于該函數(shù)的使用,請(qǐng)參考微軟的有關(guān)文獻(xiàn)。
5、結(jié)論
結(jié)構(gòu)異常處理由中斷處理和例外處理兩部分組成。采用結(jié)構(gòu)異常處理使得你可以將精力集中在你的程序應(yīng)用代碼設(shè)計(jì)上,從而使得應(yīng)用方案的設(shè)計(jì)更方便、具體。采用結(jié)構(gòu)異常處理編寫的程序更易于理解、修改和維護(hù),從而增加了程序的可讀性和維護(hù)性。

溫馨提示:喜歡本站的話,請(qǐng)收藏一下本站!

本類教程下載

系統(tǒng)下載排行

網(wǎng)站地圖xml | 網(wǎng)站地圖html
av天堂永久资源网| 天堂а在线中文在线无限看推荐| 欧美日韩成人综合天天影院| а√中文在线8| 密臀av一区二区三区| 这里只有久久精品视频| 乱色588欧美| 欧美日韩国产在线观看网站| gogo高清午夜人体在线| 麻豆影院在线| 国产精品久久久久免费a∨大胸| 欧美日韩一区综合| 九色蝌蚪国产| 中文字幕1234区| 亚洲第一二区| 国产成人在线观看网站| 中国日韩欧美久久久久久久久| 亚洲一区av在线| 这里是久久伊人| 天天操天天干天天爽| 影音先锋久久| 中文字幕视频在线免费观看| 欧美aa国产视频| 九九热这里只有精品6| 日韩三级不卡| 国产精品久久久久久久第一福利| 中文字幕综合| 少妇淫片在线影院| 日韩和的一区二在线| 日韩在线网址| 中日韩免费毛片| 无码黑人精品一区二区| 二区三区在线观看| 亚洲精华国产精华精华液网站| 中文天堂在线资源| 成人免费一区二区三区视频| 久久精品国产一区二区三区日韩| 久久亚洲精品石原莉奈| 日本视频www| 欧洲精品在线播放| 日本一级一片免费视频| 国产精品欧美久久| 一区在线观看免费| 亚洲最大视频网| 男人的天堂导航| 91麻豆精品国产91久久综合| 日本精品视频一区二区| 91麻豆精品91久久久久同性| 精品视频一区二区不卡| 国产麻豆高清视频在线第一页| 国产一区二区三区四区hd| 国产毛片久久久久久国产毛片| 性欧美freehd18| 国产高清在线一区| 九九久久免费视频| 美女被草91| 久久中文字幕在线观看| 99影视tv| 亚洲九九精品| 欧洲亚洲精品在线| 网站一区二区| 大j8黑人w巨大888a片| free性亚洲| 久久成人一区二区| 国产精品一 二 三| 91性感美女视频| 国内不卡的一区二区三区中文字幕| 日韩黄色三级视频| av网站一区| 男女性高潮免费网站| 女女百合国产免费网站| 乱熟女高潮一区二区在线| 一区二区三区中文字幕精品精品| 亚洲综合好骚| 国产一二三四五区| 国产精品成人69xxx免费视频| 性生生活性生交a级| aaa亚洲精品一二三区| 中文字幕国产精品| www.av黄色| 亚洲精品一区二区在线观看| 欧美私人情侣网站| 欧美成人三级视频| 国产区视频在线播放| 激情欧美一区二区三区| 日韩精品一区二区三区丰满| 国产欧美日韩综合精品一区二区| 黄色av资源| 1769国产精品视频| 亚洲日本中文字幕在线| 久久成人综合| 国产老妇另类xxxxx| 亚洲综合色自拍一区| 亚洲国产成人久久综合| 国产高清自拍视频在线观看| 成年人黄视频网站| 北条麻妃在线观看视频| 自拍偷自拍亚洲精品播放| 欧美色婷婷久久99精品红桃| 在线观看网站黄| bdsm在线观看播放视频| 成人短视频在线观看| 精品国产高清自在线一区二区三区| 最好看的日本字幕mv视频大全| 91骚色在线| 国产精品亚洲网站| 欧美成人黑人猛交| 福利小视频在线观看| 国产亚洲精品久久久久久无几年桃| 色哦色哦哦色天天综合| 欧美日韩一区在线观看视频| 黄色一级视频在线观看| 亚洲自拍小视频免费观看| 日韩高清影视在线观看| 欧美黑人激情| 国产成人精品无码高潮| 91精品xxx在线观看| 国产精品99久久久久久久vr| 91超碰成人| 欧美视频在线视频精品| 激情综合丁香五月| 欧美69精品久久久久久不卡| 26uuu另类欧美| 亚洲第一天堂| 亚洲高清毛片| 亚洲国产精品视频在线观看| 深夜做爰性大片蜜桃| 久久精品夜夜夜夜久久| 日韩有码第一页| 久久久久99精品成人片毛片| 一二三四在线视频观看社区| 日本不卡一区二区三区高清视频| 在线观看黄色av| 日本欧美黄色| 91国产视频在线| 一女三黑人理论片在线| 青青成人在线| 亚洲一区二区三区免费在线观看| av在线不卡精品| 亚洲色图偷窥| 亚洲视屏一区| 日韩在线观看一区二区三区| 欧美一区二区色| 在线免费看91| 色悠悠国产精品| 亚洲人成77777在线观看网| 欧美午夜激情影院| a中文在线播放| 欧美无人区码suv| 日韩人体视频一二区| 国产xxxxxxxxx| 日本在线免费看| 性欧美.com| 久99久精品视频免费观看| 91午夜在线播放| 国模大尺度一区二区三区| 午夜电影一区二区三区| 日韩人妻精品一区二区三区| 性高湖久久久久久久久| 久久99国产精一区二区三区| 在线观看不卡av| 97在线视频国产| 免费看一级一片| 欧美精品一区二区久久婷婷| 久久人妻精品白浆国产| 日韩欧美国产片| av免费在线观看网站| 成人xxxx| 久久av高潮av| 成人c视频免费高清在线观看| 国产综合成人久久大片91| 免费成人在线观看| 久久精品日产第一区二区三区乱码| 99国产精品视频免费观看| 日本一区二区三区免费观看| 欧美精选午夜久久久乱码6080| 精品国产乱码久久久久久1区2区| 欧美日韩国产乱码电影| 91麻豆精品国产综合久久久久久| 毛片网站在线看| 欧美va在线播放| 亚洲天堂av中文字幕| 九色porny视频在线观看| 麻豆视频在线播放| 欧美性色aⅴ视频一区日韩精品| 久久精品国产亚洲av麻豆| 制服丝袜在线一区| 久久午夜鲁丝片| 日韩免费观看在线观看| 国产精品h片在线播放| 天天操中文字幕视频| 国产成人午夜精品影院观看视频| 欧美猛交免费看| 日本综合一区二区三区| 亚洲第一级黄色片| 日韩av中文字幕一区| 久久这里只有精品99| 国产视色精品亚洲一区二区| 麻豆成人久久精品二区三区小说| 日韩精品视频在线观看网址| 麻豆精品视频在线| 亚洲精品在线免费| 欧美jizzhd欧美| 色999久久久精品人人澡69| 国产精品18hdxxxⅹ在线| 91精品啪在线观看国产60岁| 国产精品探花一区二区在线观看| 国产精品入口麻豆| 国模视频一区| 在线观看xxxx| 国产xxxxxx久色视频在| 欧美日韩一区久久| 久久精品国产亚洲av高清色欲| 热草久综合在线| 九色蝌蚪av新入口| 精品日韩视频在线观看| 免费黄色片网站| 三级av在线免费观看| 精品盗摄女厕tp美女嘘嘘| 91麻豆国产语对白在线观看| 韩国视频一区二区三区| 制服下的诱惑暮生| 国产a级全部精品| 福利视频一区二区三区| 免费激情视频在线观看| av毛片在线看| 91黄色在线视频| 久久久999| 天天av天天爱| 日韩一区二区三区视频| 精品国产一区二区三区四区阿崩| 成人在线观看av| 国产精彩视频一区二区| 日韩一区二区三区xxxx| 欧美xxxx中国| 色一情一欲一爱一乱| 日韩视频在线免费看| 日韩精品免费看| 欧美激情亚洲精品| 精品一区二区久久久久久久网站| 欧美成人一区二区三区| 99久久99久久精品国产片桃花| 久久综合色一综合色88| 色噜噜一区二区三区| 久久精品在这里| 伊人久久大香线蕉av一区二区| 成年网站视频| 人交獸av完整版在线观看| 亚洲一区二区免费在线观看| 91女厕偷拍女厕偷拍高清| 日韩精品一级| 国产欧美日韩另类一区| 国产精品久久婷婷六月丁香| 最爽无遮挡行房视频在线| 六月激情综合网| 日韩久久久久久久久久| 美女视频久久久| 中文字幕剧情在线观看一区| 在线免费观看中文字幕| www.黄色网| 国产精品美乳一区二区免费| 久久精品亚洲国产奇米99| 国产chinasex对白videos麻豆| 精品一区二区三区的国产在线播放| 午夜精品久久久久久久男人的天堂| 成人软件在线观看| 欧美另类z0zxhd电影| 狠狠做六月爱婷婷综合aⅴ| 伊人伊人伊人久久| 伊人国产视频| 中文字幕日韩欧美一区二区三区| 99re热这里只有精品视频| 中文一区二区完整视频在线观看| 91免费在线观看网站| 丁香六月激情综合| 亚洲免费在线观看av| 自拍偷自拍亚洲精品被多人伦好爽| 91 在线视频| 97视频久久久| 欧美成人精品欧美一级私黄| 欧美日韩大片| 最新版天堂资源在线| 男人的午夜天堂| julia中文字幕久久亚洲蜜臀| 涩涩视频在线播放| 久久久无码一区二区三区| 91国产精品91| 中文字幕无码精品亚洲35| 91久久伊人青青碰碰婷婷| 四虎成人永久免费视频| 欧美老头gaygay1069| 国产综合av在线| 国内综合精品午夜久久资源| 久久婷婷成人综合色| 爱爱爱视频网站| 国产精品久久久久久久久久免费| 午夜精品一区二区在线观看| 精品一区二区三区在线成人| 日韩大片在线观看| 欧美成人a视频| 一区二区三区美女视频| 久久99久久98精品免观看软件| 亚洲区综合中文字幕日日| 亚洲日本欧美日韩高观看| 亚洲一区二区三区四区av| 日韩 欧美 中文| 日韩欧美中文在线观看| 日本一区免费网站| 国产99精品国产| av在线播放成人| 九九久久精品这里久久网| 婷婷开心久久网| 亚洲午夜一二三区视频| 欧美精品日本| 自拍偷拍第1页| 欧美被狂躁喷白浆精品| 超碰成人在线播放| 欧美大学生性色视频| 五月天婷婷激情网| 日韩视频第一页| 亚洲欧美日韩中文字幕在线观看| 中文国产字幕在线观看| 亚洲第一天堂| 日韩一区不卡| 国产喂奶挤奶一区二区三区| 亚洲 小说区 图片区 都市| 日韩欧美在线视频观看| 精品无人乱码|