百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

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

itomcoil 2025-02-07 17:48 7 浏览

函数是程序的基本构件。函数可由三种单一入口和出口的基本控制结构(顺序、选择、循环)组成,函数内部也可以通过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.

通过此头文件setjmp.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 
#include 

void jmpfunc(jmp_buf env_buf)
{
    // ……
    printf("%s\n","③ 返回到返回点(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("④ 从 longjmp() 返回,更新上下文环境jmp_buf,并返回值 = %d\n", val);
        goto label;
    }
    printf("② 包含了jmp_buf参数和longjmp()语句的函数调用。\n");
    jmpfunc( env_buffer );
label:
    printf("⑤ 此位置非jmpfunc函数的返回地址。\n");
    getchar();
    return(0);
}
/*
① 在longjmp的预定返回点调用setjmp()保存此处的上下文环境jmp_buf,并恢复上下文环境。
② 包含了jmp_buf参数和longjmp()语句的函数调用。
③ 返回到返回点(setjmp()填充了jmp_buff的代码后)。
④ 从 longjmp() 返回,更新上下文环境jmp_buf,并返回值 = 110
⑤ 此位置非jmpfunc函数的返回地址。
*/

-End-

相关推荐

Python办公自动化系列篇之一:电子表格自动化(EXCEL)

作为高效办公自动化领域的主流编程语言,Python凭借其优雅的语法结构、完善的技术生态及成熟的第三方工具库集合,已成为企业数字化转型过程中提升运营效率的理想选择。该语言在结构化数据处理、自动化文档生成...

Python解决读取excel数据慢的问题

前言:在做自动化测试的时候,我思考了一个问题,就是如果我们的测试用例随着项目的推进越来越多时,我们做自动化回归的时间也就越来越长,其中影响自动化测试速度的一个原因就是测试用例的读取问题。用例越多,所消...

Python高效办公:用自动化脚本批量处理Excel

在现代办公环境中,Excel是处理数据的必备工具,但手动操作往往耗时且容易出错。幸运的是,Python提供了强大的库,如`openpyxl`和`pandas`,能够帮助我们高效地自动化处理Exc...

【第三弹】用Python实现Excel的vlookup功能

今天继续用pandas实现Excel的vlookup功能,假设我们的2个表长成这样:我们希望把Sheet2的部门匹在Sheet1的最后一列。话不多说,先上代码:importpandasaspd...

学习Pandas中操作Excel,看这一篇文章就够了

在数据分析和处理领域,Excel文件是常见的数据存储格式之一。Pandas库提供了强大的功能来读取、处理和写入Excel文件。本文将详细介绍如何使用Pandas操作Excel文件,包括读取、数据清洗、...

python学习笔记之pandas读取excel出现的列表显示不全问题

今天小编想改正一个表格,按照之前学习的首先导入模块importpandas读取目标excel文件data=pandas.read_excel("C:\\Users\\27195\\Des...

使用Python玩转Excel(python-excel)

Python读取Excel文件的方法主要有以下几种:Pandas库:Pandas是一个强大的数据处理库,它提供了方便的方法来读取和处理Excel文件。优点:Pandas是一个非常强大的数...

Python和Excel已经互通了,还不赶紧来学习一下

Excel是数据分析中最常用的工具,这篇文章将Python与Excel的功能对比介绍如何使用Python通过函数式编程完成Excel中的数据处理及分析工作。在Python中pandas库用于数据处理,...

python读excel文件最佳实践?直接请教pandas比gpt还好用

前言说到python读取excel文件,网上使用openpyxl的文章一大堆。我自己很少直接使用openpyxl,一般使用pandas间接使用。但如果你不希望引入pandas,该如...

用python实现execl表格内容的数据分析与处理

可以使用Python中的pandas库来处理Excel表格数据。以下是一个简单的例子:首先,安装pandas库:```pipinstallpandas```然后,读取Excel文件:```impo...

从入门到精通:Python处理Excel文件的实用技巧

在数据分析和处理的过程中,Excel是一种广泛使用的数据存储和交换格式。Python提供了多个强大的库来处理Excel文件,如pandas、openpyxl和xlrd等。本文将详细介绍...

Python自动化-Excel:pandas之concat

concatimportpandasaspds1=pd.Series([0,1,2],index=['A','B','C'])s2=p...

Python之Pandas使用系列(八):读写Excel文件的各种技巧

介绍:我们将学习如何使用Python操作Excel文件。我们将概述如何使用Pandas加载xlsx文件以及将电子表格写入Excel。如何将Excel文件读取到PandasDataFrame:和前面的...

Python操作Excel详细教程,值得收藏

Python操作Excel是一个非常强大的工具,它可以方便地处理Excel文件,例如读取、写入、格式化单元格等。以下是使用Python操作Excel的详细教程,以Excel文件名为example.xl...

python中pandas读取excel单列及连续多列数据

案例:想获取test.xls中C列、H列以后(当H列后列数未知时)的所有数据。importpandasaspdfile_name=r'D:\test.xls'#表格绝对...