c++异常管理(二)---setjmp、longjmp与自动变量

原创 2015年07月07日 10:34:03

首先上代码:

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

staticvoid f1(int,int,int,int);
staticvoid f2(void);

staticjmp_buf  jmpbuffer;
staticint      globval;    //静态全局变量,保存在bss或者data段

intmain(void)
{
        int             autoval;   //自动变量(局部变量)
        register int    regival;   // 寄存器变量,推荐保存在寄存器中。
        volatile int    volaval;   // 易失变量,每次访问都从内存中进行读取。
        static int      statval;   // 静态局部变量。

        globval = 1; autoval = 2; regival = 3; volaval = 4; statval = 5;

        if(setjmp(jmpbuffer) != 0) {
                printf("after longjmp: \n");
                printf("globval = %d, autoval = %d, regival = %d, volaval = %d, statval = %d\n",
                         globval, autoval, regival, volaval, statval);
                exit(0);
        }

        globval = 95; autoval = 96; regival = 97; volaval = 98; statval = 99;
        f1(autoval, regival, volaval, statval);
        exit(0);
}

staticvoid f1(inti, intj, intk, intl)
{
        printf("in f1():\n");
        printf("globval = %d, autoval = %d, regival = %d, volaval = %d, statval = %d\n", globval, i, j, k, l);
        f2();
}

staticvoid f2(void)
{
        longjmp(jmpbuffer, 1);
}

首先我们要搞清楚各种变量的存放位置:

  1. 自动变量: 保存在栈中
  2. 静态变量: 静态局部变量,静态全局变量。保存在 bss 或者 data 段
  3. 寄存器变量: 推荐在寄存器中进行访问。
  4. volatile 变量; 易失去的变量。 对此变量的访问需要对内存进行读取, 与编译器优化无关。

编译程序的时候不进行任何的优化:

[root@centos C]# gcc setlongjmp.c -o setlongjmp [root@centos C]#
./setlongjmp in f1(): globval = 95, autuval = 96, regival = 97,
volaval = 98, statval = 99 after longjmp: globval = 95, autoval = 96,
regival = 97, volaval = 98, statval = 99

如果是待优化的编译:

[root@centos C]# ./setlongjmp in f1(): globval = 95, autuval = 96,
regival = 97, volaval = 98, statval = 99 after longjmp: globval = 95,
autoval = 2, regival = 3, volaval = 98, statval = 99

我们可以看到

从经过优化后的代码输出可见,autoval 和 regival 这两个变量(前者是自动变量,后者是寄存器变量)的的值回滚为 main 中的初值 2 和 3 。

原因是: autoval 与 regival 本质上还是局部变量,在进行优化的时候直接采用 autoval 和 regival的操作是利用立即数来操作的,也就是说在编译器完可执行文件之后,autoval 与 regival 两个值 就以立即数存在于可执行文件了。

不带优化的代码两次的输出的结果都一样,其原因是因为不优化,所以不追求执行的效率和速度,因此各个变量的读取和写入都是老老实实的通过操作内存中的栈来进行的。

需要注意的是,全局变量,静态变量以及易失变量它们是不受优化影响的。全局变量有全局变量的存储空间,静态变量有静态变量的存储空间,易失变量它虽然没有自己特定的空间,但它不接受优化,所以它不会像上面那样和自动变量,寄存器变量被优化成“立即数”,它仍然是老老实实的入栈出栈。

结论:

所以,当我们编写一个使用非局部跳转(使用 longjmp 的跳转)的可移植程序时,必须考虑使用 volatile 属性,否贼从一个系统移植到另一个系统时,不能保证你还是原来的你,甚至是面目全非。

构建C协程之setjmp/long_jmp篇

原理简介 在标准C中的头文件中定义了一组函数 setjmp / long_jmp 用来实现“非本地跳转”的功能,利用 setjmp 可以保存当前执行线索状态,稍后通过 long_jmp 函数...
  • kobejayandy
  • kobejayandy
  • 2014年12月06日 22:16
  • 6122

setjmp和longjmp函数使用详解

非局部跳转语句---setjmp和longjmp函数。非局部指的是,这不是由普通C语言goto,语句在一个函数内实施的跳转,而是在栈上跳过若干调用帧,返回到当前函数调用路径上的某一个函数中。 #inc...
  • chenyiming_1990
  • chenyiming_1990
  • 2013年03月17日 13:34
  • 14215

C语言中利用setjmp和longjmp做异常处理

错误处理是任何语言都需要解决的问题,只有不能保证100%的正确运行,就需要有处理错误的机制。异常处理就是其中的一种错误处理方式。1 过程活动记录(Active Record)C语言中每当有一个函数调用...
  • smstong
  • smstong
  • 2016年02月24日 14:55
  • 2599

setjmp/longjmp非局部跳转函数分析

之前就一直好奇setjmp()/longjmp()函数是怎么实现非局部跳转的,心中猜测应该是通过保存调用setjmp()函数处的栈上下文(stack context),之后通过函数longjmp()来...
  • origin_lee
  • origin_lee
  • 2015年04月15日 12:13
  • 765

SIGSEGV 信号捕捉,setjmp/longjmp记录上下文跳转

在linux中编程的时候 有时候 try catch 可能满足不了我们的需求。因为碰到类似数组越界 ,非法内存访问之类的 ,这样的错误无法捕获。下面我们介绍一种使用捕获信号实现的异常 用来保证诸如段错...
  • yangyangye
  • yangyangye
  • 2015年01月21日 08:39
  • 1397

setjmp和longjmp很难和C++相处

setjmp和longjmp很难和C++相处     C程序员唯有以setjmp和longjmp才能近似这样的行为。但是longjmp在C++中有一个严重的缺陷:当它调整栈的时候,无法调用局部对...
  • chenglinhust
  • chenglinhust
  • 2013年08月15日 08:57
  • 969

C异常处理机制:setjmp和longjmp

setjmp()和longjum()是通过操纵过程活动记录实现的。它是C语言所独有的。它们部分你不了C语言有限的转移能力。这个两个函数协同工作,如下所示:     *setjmp(jmp_buf j)...
  • bytxl
  • bytxl
  • 2015年01月16日 16:18
  • 1056

setjmp和longjmp函数使用方法

非局部跳转语句—setjmp和longjmp函数。非局部指的是,这不是由普通C语言goto,语句在一个函数内实施的跳转,而是在栈上跳过若干调用帧,返回到当前函数调用路径上的某一个函数中。#includ...
  • luomoshusheng
  • luomoshusheng
  • 2015年08月17日 21:33
  • 444

关于setjmp longjmp的使用

#include #include #include #define DEBUG jmp_buf jb_env; #define CMD_ADD 1 #define CMD_SUB 2 #de...
  • u011405813
  • u011405813
  • 2013年10月19日 19:25
  • 557

setjmp和longjmp 转来的

C语言的setjmp:异常处理与构建协作式多任务系统 int setjmp(jmp_buf envbuf) 宏函数setjmp()在缓冲区envbuf中保存系统堆栈里的内容,供longjmp(...
  • ljclx1748
  • ljclx1748
  • 2013年01月21日 09:54
  • 323
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:c++异常管理(二)---setjmp、longjmp与自动变量
举报原因:
原因补充:

(最多只允许输入30个字)