《unix高级环境编程》进程环境——异常处理

         在C语言中,当嵌套函数调用出错时,可以采用非局部跳转函数setjmp和longjmp,利用这两个函数可以把程序控制流进行有效转移,这两个函数相结合可以在栈上跳过若干调用帧,返回到当前函数调用路径上的某一个函数中。

setjmp和longjmp函数

/* setjmp 和 longjmp 函数 */

/*
 * 函数功能:当某个嵌套函数出错时,可实现程序控制流跳转;
 * 函数原型:
 * #include <setjmp.h>
 * int setjmp(jmp_buf env);//若直接调用则返回0,若从longjmp调用则返回非0值;
 *
 * void longjmp(jmp_buf env, int val);
 * 说明:
 * 参数env是某种形式的数组,存放在调用longjmp时能恢复栈状态的所有信息,一般定义为全局变量;
 * val设置setjmp的返回值;
 */

测试程序

#include <setjmp.h>
#include "apue.h"

static jmp_buf env;
static int globval;//全局变量

static void fun1(int,int,int,int);
static void fun2(void);
int main(void)
{
    int autoval;//自动变量
    register int registerval;//寄存器变量
    volatile int volatileval;//易失变量
    static int staticval;//静态变量
    globval = 1; autoval = 2;
    registerval = 3; volatileval = 4;
    staticval = 5;
    if(setjmp(env) != 0)
    {
        printf("after longjmp:\n");
        printf("globval= %d, autoval= %d, registerval= %d,"
                "volatileval= %d, staticval= %d\n",
                globval,autoval,registerval,volatileval,staticval);
        printf("longjmp error\n");
        exit(0);
    }
    globval = 10; autoval = 11;
    registerval = 12; volatileval = 13;
    staticval = 14;
    fun1(autoval,registerval,volatileval,staticval);
    exit(0);
}
static
void fun1(int i, int j, int k, int l)
{
    printf("in funi():\n");
    printf("globval= %d, autoval= %d, registerval= %d,"
                "volatileval= %d, staticval= %d\n",
                globval,i,j,k,l);
    fun2();

}
static void fun2(void)
{
    longjmp(env,1);
}
输出结果:

没有优化编译的结果:

in funi():
globval= 10, autoval= 11, registerval= 12,volatileval= 13, staticval= 14
after longjmp:
globval= 10, autoval= 11, registerval= 3,volatileval= 13, staticval= 14
longjmp error
优化编译的结果:

in funi():
globval= 10, autoval= 11, registerval= 12,volatileval= 13, staticval= 14
after longjmp:
globval= 10, autoval= 2, registerval= 3,volatileval= 13, staticval= 14
longjmp error

测序讲解:

1、在main函数中,第一次直接调用setjmp时返回值是0,所以不执行main函数的打印部分,直接调用fun1函数;

2、在fun1函数中,首先打印两条语句,然后调用fun2函数。

printf("in funi():\n");
    printf("globval= %d, autoval= %d, registerval= %d,"
                "volatileval= %d, staticval= %d\n",
                i,j,k,l);

3、在fun2函数中,调用longjmp函数,相当于在这里程序出错,返回到main函数的setjmp处,这次是main函数中的setjmp返回值是val=1,则执行以下的打印信息,然后exit退出main函数:

printf("after longjmp:\n");
        printf("globval= %d, autoval= %d, registerval= %d,"
                "volatileval= %d, staticval= %d\n",
                globval,autoval,registerval,volatileval,staticval);
        printf("longjmp error\n");

        关于全局变量、自动变量、寄存器变量、易失变量、静态变量在setjmp和longjmp函数中的变化是有区别的,存放在存储器的变量将和longjmp时的值一样,存放在CPU和浮点寄存器的变量则会恢复为调用setjmp时的值。自动变量、寄存器变量存放在寄存器中,所以其变量值恢复到调用setjmp时的值,全局变量、易失变量、静态变量存放在存储器中,所以变量将和longjmp时的值一样。


参考资料:

《unix高级环境编程》

你可能感兴趣的:(Unix高级环境编程,进程环境,longjmp函数,setjmp函数)