天天看点

C Interfaces and Implementations 关于setjmp,longjmp和volatile

问题出自:

C Interfaces and Implementations:Chapter 4 Exceptions and Assertions

书中提到c语言中setjmp.h里的

setjmp(jmp_buf env)

longjmp(jmp_buf env,int val)

以前从来没有见到过这两个函数,看完这一章也不是很明白这两个函数到底有什么用,回来百度之

int setjmp(jmp_buf envbuf);
           

c++ reference :

Save calling environment for long jump

This macro with functional form fills env with information about the current state of the calling environment in that point of code execution, so that it can be restored by a later call to longjmp.

Calling longjmp with the information stored in env restores this same state and returns the control to that same point (the call to setjmp), which is evaluated as a particular non-zero value.

The state of the calling environment includes the values of all accessible objects, except those of automatic duration local to the function which do not have volatile-qualified types and which change before the call to longjmp; these have indeterminate values.

The invocation of setjmp shall be an expression statement by itself, or be evaluated in a selection or iteration statement either as the (potentially negated) entire controlling expression or compared against an integer constant expression. Otherwise, it causes undefined behavior.

Return Value:

This macro may return more than once: A first time, on its direct invocation; In this case it always returns zero.

When longjmp is called with the information set to env, the macro returns again; this time it returns the value passed to longjmp as second argument if this is different from zero, or 1 if it is zero.

翻译一下:

为longjump存储调用函数时的上下文环境

setjmp(env)

函数会在调用时保存当时的上下文环境,以便于后面

longjmp(env,val)

函数的调用

‘上下文环境’包括:所有可以访问的对象,除了那些没有volatile属性的函数内的局部变量和longjmp被调用之前被更改的变量。

第三段是setjmp的一些使用条件

返回值:

第一次调用setjmp时一定返回0,

之后调用longjmp时setjump也会返回值,值为longjmp的第二个参数

void longjmp(jmp_buf envbuf, int val)
           

Restores the environment to the state indicated by env, evaluating the setjmp expression that filled env as val.

The function never returns to the point where it has been invoked. Instead, the function transfers the control to the point where setjmp was last used to fill the env, and evaluates the whole expression as val (unless this is zero, in which case it evaluates as value of 1).

If env was not filled by a previous call to setjmp or if the function with such call has terminated execution, it causes undefined behavior.

In C++, the implementation may perform stack unwinding that destroys objects with automatic duration. If this invokes any non-trivial destructors, it causes undefined behavior.

上面一大堆简单来说就是:

longjmp函数中的参数envbuf是由setjmp函数所保存过的堆栈环境,参数val设置setjmp函数的返回值。longjmp函数本身是没有返回值的,它执行后控制流跳转到保存envbuf参数的setjmp函数调用,并由setjmp函数调用返回,此时setjmp函数的返回值就是val。

下面是实例:

#include <stdio.h> 
#include <setjmp.h>  
 jmp_buf buf; 
 banana(){ 
    printf("in banana() \n"); 
    longjmp(buf,); 
     printf("you'll never see this,because i longjmp'd"); 
 } 
 main() 
{ 
    if(setjmp(buf)) 
        printf("back in main\n"); 
    else{ 
        printf("first time through\n"); 
        banana(); 
    } 
 }
           

输出是这样的:

first time through
in banana()
back in main
           

仔细看一下应该更能体会这对函数的作用

setjmp/longjmp的最大用处是错误恢复,类似try …catch…

他们的功能比goto强多了,goto只能在函数体内跳来跳去,而setjmp/longjmp可以在到过的所有位置间。

Volatile

参考:

http://www.cnblogs.com/yc_sunniwell/archive/2010/06/24/1764231.html

简单来说就是声明了volatile属性的变量不会因为编译器优化代码而对这个代码本来的意图产生影响

继续阅读