setjmp, longjmp
Header Files
#include <setjmp.h>
Function Prototype
int setjmp(jmp_buf env);
int longjmp(jmp_buf env, int val);env
jmp_buf 是 array type,所以當我們將 env 作為參數時,實際上是傳入 env 第一個元素的地址
Function
setjmp
setjmp()會記錄當前程序的執行狀態在env中- 直接呼叫
setjmp()回傳值是 0 - 否則因為
longjmp()而回到這行則會回傳longjmp()參數中的val
longjmp
longjmp()會回到env當前紀錄的狀態,包括 stack pointer、CPU register、return address 等
如果要在 signal handler 中進行
longjmp,你必須確保setjmp已經執行完成我們的方法是使用
sig_atomic_t變數在setjmp後設為 true 並在 handler 中檢查
Effects on Variables
Effects on Automatic, Register, and Volatile Variables
對於一些 local variable,編譯器可能因為優化而將其放在 register 而非 stack frame 上面,而在 longjmp() 後 register 會回復原樣而 stack frame 上的變數不會
auto
我們沒有指定其放在哪裡,所以他的值在 longjmp() 後是否會改變是未定義的
register
register 變數因為會在 setjmp() 時存在 jmp_buf 中,所以 longjmp() 回來後會回復成 setjmp() 時的狀態
volatile
volatile 會強制將變數放在 stack frame 上而非 register,所以 longjmp() 後並不會回復成 setjmp() 時的值
Effects on Global Variables
因為 global variable 存在 virtual memory 的 initialized data 或 uninitialized data 處,所以不會因為 longjmp() 而回復狀態
Example
Code
#include <setjmp.h>
#include <stdio.h>
jmp_buf env;
int global_var = 100; // 全域變數
static int static_var = 200; // 靜態變數
void deep_function() {
// 在這裡修改各種變數,然後跳回去
global_var = 999;
static_var = 999;
printf("在 deep_function 中,準備 longjmp...\n");
longjmp(env, 1); // 跳回 main 中 setjmp 的位置
}
int main() {
// 這些是 main 的區域變數
int auto_var = 300; // 自動變數
register int reg_var = 400; // 暫存器變數(提示編譯器)
volatile int volatile_var = 500; // volatile 區域變數
int ret = setjmp(env); // 設定跳躍點
if (ret == 0) {
// 第一次執行:修改所有變數
printf("第一次執行 setjmp,返回 0\n");
printf("修改前:auto_var=%d, reg_var=%d, volatile_var=%d\n",
auto_var, reg_var, volatile_var);
// 修改這些變數
auto_var = 777;
reg_var = 888;
volatile_var = 666;
printf("修改後:auto_var=%d, reg_var=%d, volatile_var=%d\n",
auto_var, reg_var, volatile_var);
deep_function(); // 這會觸發 longjmp
printf("這行永遠不會執行\n");
} else {
// 從 longjmp 跳回來
printf("\n從 longjmp 回來了!返回值 = %d\n", ret);
printf("跳回來後:auto_var=%d, reg_var=%d, volatile_var=%d\n",
auto_var, reg_var, volatile_var);
printf("全域變數:global_var=%d, static_var=%d\n",
global_var, static_var);
}
return 0;
}Output
第一次執行 setjmp,返回 0
修改前:auto_var=300, reg_var=400, volatile_var=500
修改後:auto_var=777, reg_var=888, volatile_var=666
在 deep_function 中,準備 longjmp...
從 longjmp 回來了!返回值 = 1
跳回來後:auto_var=777, reg_var=400, volatile_var=666
全域變數:global_var=999, static_var=999