第5章 进程环境(5)_非局部跳转
6. 非局部跳转
(1)setjmp和longjmp语句
|
头文件 |
#include<setjmp.h> |
|
函数 |
int* setjmp(jum_buf env); |
|
返回值 |
直接调用返回0,若从longjmp调用返回则返回非0值 |
|
功能 |
设置非局部跳转的跳转点 |
|
|
|
|
函数 |
void longjmp(jmp_buf env, int val); |
|
功能 |
进行非局部转转,val为返回值 |
|
参数 |
env:一个特殊类型jmp_buf。这一数据类型是某种形式的数组,其中存放在调用longjmp时能用来恢复栈状态的信息(如,各寄存器的值;但不保存线程栈局部变量等数据)。一般,env变量是个全局变量,因为需要从另一个函数引用它。 |
|
备注 |
(1)C程序缺乏异常处理方法,可使用非局部跳转处理C程序的异常。 (2)goto语句仅限于函数内部跳转,而longjmp不限于。 |
【编程实验】非局部跳转
//process_jmp.c
#include <setjmp.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TOK_ADD 5
#define TOK_SUB 6
char* const prompt = "cal: "; //命令行提示符
jmp_buf env; //保存运行环境,非局部跳转用于函数间的跳转
//命令行格式如:add 3 5 或 sub 5 3
void do_line(char* line); //解析并执行命令行内容
void cmd_add(void);
void cmd_sub(void);
int get_token(char* line); //从命令行参数中获取标识符
int main(int argc, char* argv[])
{
ssize_t size = strlen(prompt) * sizeof(char);
char buff[256];
ssize_t len = 0;
//设置跳转点
if(setjmp(env) < 0){ //直接调用返回0,从longjmp跳转来时,返回longjmp中指定的val值
//这里我们设定val为正值,小于0表示setjmp调用失败!
perror("setjmp error");
exit(1);
}
//输出提示符
write(STDOUT_FILENO, prompt, size);
while(1)
{
len = read(STDIN_FILENO, buff, 256);
if(len < 0) break;
buff[len -1] = 0;
do_line(buff);
write(STDOUT_FILENO, prompt, size);
}
return 0;
}
void do_line(char* line)
{
int cmd = get_token(line);
switch(cmd)
{
case TOK_ADD:
cmd_add();
break;
case TOK_SUB:
cmd_sub();
break;
default:
fprintf(stderr, "error command\n");
}
}
void cmd_add(void)
{
int i = get_token(NULL);
int j = get_token(NULL);
printf("result: %d + %d = %d\n", i, j, i + j);
}
void cmd_sub(void)
{
int i = get_token(NULL);
int j = get_token(NULL);
printf("result: %d - %d = %d\n", i, j, i - j);
}
static int is_number(char* item)
{
int ret = 1;
int len = strlen(item);
int i = 0;
for(i=0; i<len; i++) {
ret = ret && ('0'<= item[i]) && (item[i] <= '9');
if (ret == 0) break;
}
return ret;
}
int get_token(char* line)
{
//格式add 3 4
// sub 7 5
char* item = strtok(line, " ");
if(line != NULL)
{
if(!strcmp("add", item)) return TOK_ADD;
if(!strcmp("sub", item)) return TOK_SUB;
}else{
if(is_number(item)){
int i = atoi(item);
return i;
}else{
fprintf(stderr, "arg not number\n");
longjmp(env, 1); //1表示跳到跳转点(setjmp)后,setjmp的返回值
}
}
}
(2)longjmp对各类变量的影响
|
变量类型 |
受影响情况 |
|
全局变量、静态变量和volatile变量 |
不能恢复到原始值 |
|
寄存器变量 |
可以恢复到原始值 |
|
自动变量 |
优化编译后可能会恢复 |
①存放在存储器中的变量将具有longjmp时的值,而在cpu和浮点寄存器中的变量则恢复为调用setjmp时的值。
②不进行优化时,自动变量、寄存器变量、全局变量、静态变量和易失变量等都存放在存储器中(亦即忽略了对reg_var变量的register存储类说明)。
③而进行了优化后,auto_var和reg_var都存放在寄存器中(即使auto_var并未声明为register),volatile变量则仍存放在存储器中。
④全局、静态和易失变量不受优化的影响,在调用longjmp后,它们的值是最近所呈现的值。
⑤如果要编写一个使用非局部跳转的可移植程序,则必须使用volatile属性。
【编程实验】longjmp对变量的影响
//longjmp_var.c
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int global_var;
jmp_buf env;
int show(int g_v, int s_v, int a_v, int r_v, int m_v, int v_v);
int f1(int g_v, int s_v, int a_v, int r_v, int m_v, int v_v);
void f2();
int main(int argc, char* argv[])
{
static int sta_var;
int auto_var;
register reg_var;
int* heap_var = (int*)malloc(sizeof(int));
volatile int vola_var;//易失变量
global_var = 1; sta_var = 2; auto_var = 3;
reg_var = 4; *heap_var = 5; vola_var = 6;
int k = 0;
if((k = setjmp(env)) < 0 ){
perror("setjmp error");
}else if(k == 1){
printf("after longjmp:\n");
show(global_var, sta_var, auto_var, reg_var, *heap_var, vola_var);
exit(0);
}
global_var = 10; sta_var = 20; auto_var = 30;
reg_var = 40; *heap_var = 50; vola_var = 60;
printf("before longjmp:\n");
f1(global_var, sta_var, auto_var, reg_var, *heap_var, vola_var);
return 0;
}
int show(int g_v, int s_v, int a_v, int r_v, int m_v, int v_v)
{
printf(" global: %d, static: %d, auto: %d, reg: %d, heap: %d vola: %d\n",
g_v, s_v, a_v, r_v, m_v, v_v);
}
int f1(int g_v, int s_v, int a_v, int r_v, int m_v, int v_v)
{
show(g_v, s_v, a_v, r_v, m_v, v_v);
f2();
}
void f2()
{
longjmp(env, 1);
}
/*输出结果:
[root@bogon 5.process]# gcc -o bin/longjmp_var src/longjmp_var.c
[root@bogon 5.process]# bin/longjmp_var
before longjmp:
global: 10, static: 20, auto: 30, reg: 40, heap: 50 vola: 60
after longjmp:
global: 10, static: 20, auto: 30, reg: 40, heap: 50 vola: 60
[root@bogon 5.process]# gcc -O -o bin/longjmp_var src/longjmp_var.c
[root@bogon 5.process]# bin/longjmp_var
before longjmp:
global: 10, static: 20, auto: 30, reg: 40, heap: 50 vola: 60
after longjmp:
global: 10, static: 20, auto: 3, reg: 4, heap: 50 vola: 60
*/

浙公网安备 33010602011771号