setjmp與longjmp 尾碼jmp指的就是jump,關看名字就能猜到這哥倆是幹啥的了。使用他們倆就可以讓程式控制流轉移,進而實現對異常的處理。 異常處理的結構可以劃分為以下三個階段: 準備階段:在內核棧保存通用寄存器內容 處理階段:保存硬體出錯碼和異常類型號,然後向當前進程發送信號 恢復階段: ...
setjmp與longjmp
尾碼jmp指的就是jump,關看名字就能猜到這哥倆是幹啥的了。使用他們倆就可以讓程式控制流轉移,進而實現對異常的處理。
異常處理的結構可以劃分為以下三個階段:
- 準備階段:在內核棧保存通用寄存器內容
- 處理階段:保存硬體出錯碼和異常類型號,然後向當前進程發送信號
- 恢復階段:恢復保存在內核棧中的各個寄存器內容,返回當前進程的斷電處繼續執行
過程有點類似遞歸,只有文字你可能看的有點雲里霧裡,我們結合一個小例子來看看
#include <stdio.h>
#include <setjmp.h>
static jmp_buf buf;
void second(void) {
printf("second\n");
// 跳回setjmp的調用處 - 使得setjmp返回值為1
longjmp(buf, 1);
}
void first(void) {
second();
//這行到不了,因為second裡面longjmp已經跳轉回去了
printf("first\n");
}
int main() {
int rc;
rc = setjmp(buf);
if (rc==0) {
// 進入此行前,setjmp返回0
first();
}
// longjmp跳轉回,setjmp返回1,因此進入此行
else if(rc==1){
printf("main\n");
}
return 0;
}
/*
the ressult as:
second
main
*/
現在我們再來看看兩個函數的聲明:
- setjmp(env) :將程式上下文存儲在env中
- longjmp(env,status):env指代setjmp中所保存的函數執行狀態變數,status則是作為setjmp的返回值
當然你也可以用switch
代替上面的if else
,其實try catch就相當於上面的那個函數你可以參考這個實現try catch。
signal信號處理
個人覺得這個在linux下更好用,並且也提供了更多的信號量巨集。
下麵給出的是signal頭文件中的定義
#define SIGINT 2 // interrupt
#define SIGILL 4 // illegal instruction - invalid function image
#define SIGFPE 8 // floating point exception
#define SIGSEGV 11 // segment violation
#define SIGTERM 15 // Software termination signal from kill
#define SIGBREAK 21 // Ctrl-Break sequence
#define SIGABRT 22 // abnormal termination triggered by abort call
這裡僅給出維基上的例子
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
static void catch_function(int signal) {
puts("Interactive attention signal caught.");
}
int main(void) {
if (signal(SIGINT, catch_function) == SIG_ERR) {
fputs("An error occurred while setting a signal handler.\n", stderr);
return EXIT_FAILURE;
}
puts("Raising the interactive attention signal.");
if (raise(SIGINT) != 0) {
fputs("Error raising the signal.\n", stderr);
return EXIT_FAILURE;
}
puts("Exiting.");
return 0;
}