異常處理,保證程式碼穩定的必經之步----小話c語言(12)
阿新 • • 發佈:2019-02-05
[Mac 10.7.1 Lion Intel-based x64 gcc4.2.1]
Q: c語言的異常處理可以使用什麼?
A: 可以使用setjmp和longjmp的組合。一個是儲存處理異常前執行的環境,一個是調回原來執行的環境。
int setjmp(jmp_buf env);
引數env的型別jmp_buf定義如下:/* * _JBLEN is number of ints required to save the following: * eax, ebx, ecx, edx, edi, esi, ebp, esp, ss, eflags, eip, * cs, de, es, fs, gs == 16 ints * onstack, mask = 2 ints */ #define _JBLEN (18) typedef int jmp_buf[_JBLEN];
可以看到jmp_buf是個陣列型別,含有18個int型別資料,包括eax, ebp, esp, eip等環境變數。
它會返回0,便於外部判斷進入異常處理邏輯。
void longjmp(jmp_buf env, int val);
第一個引數為setjmp設定的jmp_buf, 第二個引數為返回異常處理的異常引數,可自定義。下面是個簡單的例子:
可以看到setjmp和longjmp因為共同操作了jmp_buf buf;全域性變數,所以它們可以在不同函式跳轉並正確返回執行。main函式開始setjmp(buf)一定會返回0, 所以進入exception_process例程,進入後,longjmp(buf, 1);會返回之前執行的地方,進入main的if(ret)邏輯中,執行異常發生後的程式碼。#include <stdio.h> #include <string.h> #include <setjmp.h> #define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue)); #define PRINT_STR(str) printf(#str" is %s\n", (str)); jmp_buf buf; // exception process void exception_process() { printf("exception process begin...\n"); longjmp(buf, 1); // return to the normal process printf("never execute this...\n"); // so, this line can't be executed } int main() { int ret; printf("main begin...\n"); ret = setjmp(buf); // save current execute enviroment, go to exception process if(ret) { // returned by exception process printf("pass exception process ...\n"); printf("main end ...\n"); } else { exception_process(); } return 0; }
執行結果:
Q: 上面程式碼中的buf全域性變數可以採用區域性變數嗎?
A: 是的,但是需要將buf傳遞給異常處理部分。如下程式碼:
可以看到exception_process多了一個引數,用於buf的傳遞。#include <stdio.h> #include <string.h> #include <setjmp.h> #define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue)); #define PRINT_STR(str) printf(#str" is %s\n", (str)); // exception process void exception_process(jmp_buf buf) { printf("exception process begin...\n"); longjmp(buf, 1); // return to the normal process printf("never execute this...\n"); // so, this line can't be executed } int main() { jmp_buf buf; int ret; printf("main begin...\n"); ret = setjmp(buf); // save current execute enviroment, go to exception process if(ret) { // returned by exception process printf("pass exception process ...\n"); printf("main end ...\n"); } else { exception_process(buf); } return 0; }
執行結果:
Q: 如果異常原因有幾種,怎麼分辨處理?
A: 這個就需要用到longjmp第二個引數了。
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue));
#define PRINT_STR(str) printf(#str" is %s\n", (str));
// input error process
void exception_input_error_process(jmp_buf buf)
{
printf("exception input error process begin...\n");
longjmp(buf, 1001); // return to the normal process, 1001 means exception error number
}
// input too big process
void exception_input_too_big_process(jmp_buf buf)
{
printf("exception input too big process begin...\n");
longjmp(buf, 1002); // return to the normal process, 1002 means exception error number
}
int main()
{
jmp_buf buf;
int ret, scanf_ret;
int n;
printf("main begin...\n");
// input n
printf("input n:");
scanf_ret = scanf("%d", &n);
ret = setjmp(buf); // save current execute enviroment, go to exception process
if(ret)
{
// returned by exception process
printf("pass exception process ...\n");
if(ret == 1001)
{
printf("exception 1001 process end...\n");
}
else if(ret == 1002)
{
printf("exception 1002 process end...\n");
}
printf("main end ...\n");
}
else
{
if(scanf_ret < 1)
exception_input_error_process(buf);
else if(n > 100)
exception_input_too_big_process(buf);
}
return 0;
}
如上,如果輸入整形格式不正確,那麼進入輸入錯誤處理;如果輸入的整形超過100,那麼進入輸入過大的處理。執行結果:
輸入錯誤資料a:
輸入資料為101:
輸入資料50:
此時沒有發生異常。
xichen
2012-5-18 15:18:16