您的位置 首页 java

C|函数的调用与返回,本地与非本地跳转

函数是程序的基本构件。函数可由三种单一入口和出口的基本控制结构(顺序、选择、循环)组成,函数内部也可以通过goto实现局部跳转,函数之间能够通过栈机制实现函数调用和返回,类似的,通过适当的语法机制来保存上下文环境,函数之间也能实现非局部跳转。

1 函数调用与返回

主调函数调用被调函数,流程控制从主调函数跳转到被调函数之前,上下文环境保存在栈帧上,被调函数执行完后,返回到被调函数的调用点之后:

2 goto局部跳转

我们知道,汇编语言可以实现条件或无条件跳转,在高级语言中, goto语句 也可以跳转。在 结构体 编程语言中,程序块由顺序、选择、循环三种结构取代。

3 非局部跳转(Non local jumps)

The tools provided through the header file setjmp.h allow the programmer to bypass the normal function call and return discipline, by providing the means to perform jumps preserving the calling environment.

通过此头文件set jmp .h提供的工具, 程序员 可以通过提供执行跳转的方法来保留调用环境,从而绕过正常的函数调用和返回规程。

The header provides, a function, a macro with functional form and a specific type:

头文件提供函数、宏以及函数形式和特定类型:

3.1 setjmp()

在特定的需要函数的返回点调用setjmp即可以保存该处的上下文环境(jmp_buf):

 typedef  struct  __JUMP_BUFFER {
     unsigned  long Ebp;
    unsigned long Ebx;
    unsigned long Edi;
    unsigned long Esi;
    unsigned long Esp;
    unsigned long Eip;
    unsigned long Registration;
    unsigned long TryLevel;
    unsigned long Cookie;
    unsigned long UnwindFunc;
    unsigned long UnwindData[6];
} _JUMP_BUFFER;

# define  _JBLEN  16
#define _JBTYPE int
 typedef  _JBTYPE jmp_buf[_JBLEN];

int setjmp (jmp_buf env);  

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.

这个函数形式的宏向env填充了关于代码执行点中调用环境的当前状态的信息,以便稍后调用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.

使用存储在env中的信息调用longjmp会恢复相同的状态,并将控制返回到相同的点(对setjmp的调用),该点被计算为特定的非零值。

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.

调用环境的状态包括所有可访问对象的值,但函数本地的自动持续时间对象除外,这些对象没有易失性限定类型,并且在调用longjmp之前更改;这些值不确定。

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.

setjmp的调用本身应该是一个表达式语句,或者在选择或迭代语句中作为(可能被否定的)整个控制表达式进行计算,或者与整数常量表达式进行比较。否则,会导致未定义的行为。Restores the environment to the state indicated by env, evaluating the setjmp expression that filled env as val.

3.2 longjmp

将环境恢复到env指示的状态,并将填充env的setjmp表达式计算为val。

  void  longjmp (jmp_buf env, int val);  

The called function containing the longjmp() macro 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).

包含longjmp()宏的被调函数永远不会返回到调用它的位置。相反,该函数将控件传输到上次使用setjmp填充env的位置,并将整个表达式计算为val(除非这是零,在这种情况下,它计算为值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.

如果之前对setjmp的调用未填充env,或者具有此类调用的函数已终止执行,则会导致未定义的行为。

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.

在C++中,实现可以执行堆栈展开,以自动持续时间销毁对象。如果这调用任何非平凡的 析构函数 ,则会导致未定义的行为。

demo code:

 // setjmp和longjmp
# include  <stdio.h>
#include <setjmp.h>

void jmpfunc(jmp_buf env_buf)
{
    // ……
     printf ("%sn","③ 返回到返回点(setjmp()填充了jmp_buff的代码后)。");
    longjmp(env_buf, 110);
}
int main()
{
    int val;
    jmp_buf env_buffer;
    
    printf("① 在longjmp的预定返回点调用setjmp()保存此处的上下文环境jmp_buf,并恢复上下文环境。n");
    val = setjmp( env_buffer );
    // longjmp返回点
    if( val != 0 ) 
    {
        printf("④ 从  long jmp() 返回,更新上下文环境jmp_buf,并返回值 = %dn", val);
        goto label;
    }
    printf("② 包含了jmp_buf参数和longjmp()语句的函数调用。n");
    jmpfunc( env_buffer );
label:
    printf("⑤ 此位置非jmpfunc函数的返回地址。n");
    get char ();
    return(0);
}
/*
① 在longjmp的预定返回点调用setjmp()保存此处的上下文环境jmp_buf,并恢复上下文环境。
② 包含了jmp_buf参数和longjmp()语句的函数调用。
③ 返回到返回点(setjmp()填充了jmp_buff的代码后)。
④ 从 longjmp() 返回,更新上下文环境jmp_buf,并返回值 = 110
⑤ 此位置非jmpfunc函数的返回地址。
*/  

-End-

文章来源:智云一二三科技

文章标题:C|函数的调用与返回,本地与非本地跳转

文章地址:https://www.zhihuclub.com/178272.shtml

关于作者: 智云科技

热门文章

网站地图