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

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

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

函数是程序的基本构件。函数可由三种单一入口和出口的基本控制结构(顺序、选择、循环)组成,函数内部也可以通过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创建文件夹,轻松搞定,喝咖啡去了

最近经常在录视频课程,一个课程下面往往有许多小课,需要分多个文件夹来放视频、PPT和案例,这下可好了,一个一个手工创建,手酸了都做不完。别急,来段PYTHON代码,轻松搞定,喝咖啡去了!import...

如何编写第一个Python程序_pycharm写第一个python程序

一、第一个python程序[掌握]python:python解释器,将python代码解释成计算机认识的语言pycharm:IDE(集成开发环境),写代码的一个软件,集成了写代码,...

Python文件怎么打包为exe程序?_python3.8打包成exe文件

PyInstaller是一个Python应用程序打包工具,它可以将Python程序打包为单个独立可执行文件。要使用PyInstaller打包Python程序,需要在命令行中使用py...

官方的Python环境_python环境版本

Python是一种解释型编程开发语言,根据Python语法编写出来的程序,需要经过Python解释器来进行执行。打开Python官网(https://www.python.org),找到下载页面,选择...

[编程基础] Python配置文件读取库ConfigParser总结

PythonConfigParser教程显示了如何使用ConfigParser在Python中使用配置文件。文章目录1介绍1.1PythonConfigParser读取文件1.2Python...

Python打包exe软件,用这个库真的很容易

初学Python的人会觉得开发一个exe软件非常复杂,其实不然,从.py到.exe文件的过程很简单。你甚至可以在一天之内用Python开发一个能正常运行的exe软件,因为Python有专门exe打包库...

2025 PyInstaller 打包说明(中文指南),python 打包成exe 都在这里

点赞标记,明天就能用上这几个技巧!linux运维、shell、python、网络爬虫、数据采集等定定做,请私信。。。PyInstaller打包说明(中文指南)下面按准备→基本使用→常用...

Python自动化办公应用学习笔记40—文件路径2

4.特殊路径操作用户主目录·获取当前用户的主目录路径非常常用:frompathlibimportPathhome_dir=Path.home()#返回当前用户主目录的Path对象...

Python内置tempfile模块: 生成临时文件和目录详解

1.引言在Python开发中,临时文件和目录的创建和管理是一个常见的需求。Python提供了内置模块tempfile,用于生成临时文件和目录。本文将详细介绍tempfile模块的使用方法、原理及相关...

python代码实现读取文件并生成韦恩图

00、背景今天战略解码,有同学用韦恩图展示各个产品线的占比,效果不错。韦恩图(Venndiagram),是在集合论数学分支中,在不太严格的意义下用以表示集合的一种图解。它们用于展示在不同的事物群组之...

Python技术解放双手,一键搞定海量文件重命名,一周工作量秒搞定

摘要:想象一下,周五傍晚,办公室的同事们纷纷准备享受周末,而你,面对着堆积如山的文件,需要将它们的文件名从美国日期格式改为欧洲日期格式,这似乎注定了你将与加班为伍。但别担心,Python自动化办公来...

Python路径操作的一些基础方法_python路径文件

带你走进@机器人时代Discover点击上面蓝色文字,关注我们Python自动化操作文件避开不了路径操作方法,今天我们来学习一下路径操作的一些基础。Pathlib库模块提供的路径操作包括路径的...

Python爬取下载m3u8加密视频,原来这么简单

1.前言爬取视频的时候发现,现在的视频都是经过加密(m3u8),不再是mp4或者avi链接直接在网页显示,都是经过加密形成ts文件分段进行播放。今天就教大家如果通过python爬取下载m3u8加密视频...

探秘 shutil:Python 高级文件操作的得力助手

在Python的标准库中,shutil模块犹如一位技艺精湛的工匠,为我们处理文件和目录提供了一系列高级操作功能。无论是文件的复制、移动、删除,还是归档与解压缩,shutil都能以简洁高效的方式完成...

怎么把 Python + Flet 开发的程序,打包为 exe ?这个方法很简单!

前面用Python+Flet开发的“我的计算器v3”,怎么打包为exe文件呢?这样才能分发给他人,直接“双击”运行使用啊!今天我给大家分享一个简单的、可用的,把Flet开发的程序打包为...