c语言中的局部跳转以及全局跳转

一、前言

在c语言中,当我们在处理某些异常情况的时候,经常会使用goto语句来进行跳转。goto用起来很方便,但可能很多人都不知道,goto只能在一个函数里面跳转,并不能够跨函数跳转。本文将介绍能够跨函数跳转的接口setjmp和longjmp,将围绕如下内容展开:
1.goto的局限性
2.进程运行时的栈帧结构
3.setjmp和longjmp简介和使用方法
4.使用了全局跳转后main中变量的状态

二、goto的局限性

goto只能在同一个函数里面跳转,无法从一个函数跳转到另一个函数中。如果试图从一个函数跳转到另一个函数,则编译会报错。参考代码如下:

/*************************************************************************> File Name: goto_test.c> Author: conbiao> Created Time: 2024年09月13日 星期五 10时47分41秒************************************************************************//************************************************************************                             HEADER**********************************************************************/
#include<stdio.h>/************************************************************************                              MACRO**********************************************************************//************************************************************************                          GLOBAL VARIABLE**********************************************************************//************************************************************************                       FUNCTION DESCRIPTION**********************************************************************/
void goto_test(void);/***********************************************************************
* FUNCTION NAME: void goto_test()***********************************************************************
*
* Summary:
*       This function is used to test goto.
*
* Params:
*       NONE.
*
* Return:
*       NONE.
*
***********************************************************************/
void goto_test(void)
{int i;start:i = 0;printf("%s: start!\n",__func__);while(1){printf("%s: i = %d\n",__func__,i++);if(i > 5)goto main_start;}
}/************************************************************************                                MAIN**********************************************************************/
int main(int argc, char *argv[])
{int ret = 0;
main_start:printf("%s: start!\n",__func__);goto_test();return ret;
}

编译结果如下:
在这里插入图片描述

(2-1)
如果在同一个函数中使用goto,则能够正常跳转,代码如下:

/*************************************************************************> File Name: goto_test.c> Author: conbiao> Created Time: 2024年09月13日 星期五 10时47分41秒************************************************************************//************************************************************************                             HEADER**********************************************************************/
#include<stdio.h>/************************************************************************                              MACRO**********************************************************************//************************************************************************                          GLOBAL VARIABLE**********************************************************************//************************************************************************                       FUNCTION DESCRIPTION**********************************************************************/
void goto_test(void);/***********************************************************************
* FUNCTION NAME: void goto_test()***********************************************************************
*
* Summary:
*       This function is used to test goto.
*
* Params:
*       NONE.
*
* Return:
*       NONE.
*
***********************************************************************/
void goto_test(void)
{int i;start:i = 0;printf("%s: start!\n",__func__);while(1){printf("%s: i = %d\n",__func__,i++);if(i > 5)goto start;}
}/************************************************************************                                MAIN**********************************************************************/
int main(int argc, char *argv[])
{int ret = 0;
main_start:printf("%s: start!\n",__func__);goto_test();return ret;
}

运行结果如下:
在这里插入图片描述

(2-2)

三、进程运行时的栈帧结构

在https://editor.csdn.net/md/?articleId=142054973一节中已经介绍过c程序运行时的存储空间布局,这其实是一个进程的进程空间结构。其中,栈空间用于存储程序在运行过程中使用到的临时变量,在进程空间中,系统为每个函数分配一个栈帧,结构如下:

在这里插入图片描述

goto只能在其调用函数的栈帧中跳转,无法从一个栈帧跳转到另一个栈帧。

四、setjmp和longjmp

使用setjmp和longjmp能够实现在栈帧上进行跳跃,其中setjmp用于设置标记,它会保存当前的执行环境(如程序计数器、栈指针等)在调用longjmp后,会恢复之前保存的执行环境,相当于跳转到setjmp的位置,。

4.1 setjmp

setjmp的函数实现如下:

头文件:#include <setjmp.h>
函数原型: int setjmp(jmp_buf env);
返回值
如果 setjmp 是直接调用的,它将返回 0。
如果 setjmp 是通过 longjmp 调用的,它将返回 longjmp 的第二个参数(非零值)。
传入参数
jmp_buf env:这是一个用于存储执行环境的数组类型。setjmp 会将当前的执行环境保存到这个数组中。

4.2 longjmp

longjmp的函数原型如下:

头文件: #include <setjmp.h> 函数原型: void longjmp(jmp_buf env, int val);
传入参数:
jmp_buf env:这是之前由 setjmp 保存的执行环境。
int val:这是 longjmp 返回给 setjmp 的值。通常是一个非零值,用于区分不同的跳转点。

4.3 参考代码

/*************************************************************************> File Name: jump_test.c> Author: conbiao> Created Time: 2024年09月13日 星期五 14时24分11秒************************************************************************//************************************************************************                             HEADER**********************************************************************/
#include<stdio.h>
#include<setjmp.h>/************************************************************************                              MACRO**********************************************************************//************************************************************************                          GLOBAL VARIABLE**********************************************************************/
jmp_buf env;
static int i = 0;/************************************************************************                       FUNCTION DESCRIPTION**********************************************************************/
void func1(void);/***********************************************************************
* FUNCTION NAME:***********************************************************************
*
* Summary:
*
* Params:
*
* Return:
*
***********************************************************************/
void func1(void)
{printf("%s: start!\n",__func__);while(i < 8){longjmp(env,i++);}}/************************************************************************                                MAIN**********************************************************************/
int main(int argc, char *argv[])
{int ret = 0;ret = setjmp(env);if(ret == 0){printf("%s: This is the first call setjump!\n",__func__);}else{printf("%s: This is return from longjmp! ret = %d\n",__func__,ret);}func1();return ret;
}

运行结果如下:
在这里插入图片描述

(4.3-1)
可见,使用setjmp和longjmp实现了从func1的栈帧跳转到main函数所在的栈帧的功能。

分析一下上面代码的执行过程,在main函数调用setjmp前,该进程的栈如下:
在这里插入图片描述

(4.3-2)
到执行func1函数,调用longjmp前,栈空间如下:
在这里插入图片描述

(4.3-3)
在setjmp时,会将当前的执行环境信息保存到env中,当执行longjmp时,栈空间会回到4.3-2的情况,func1的栈帧就没有了。

五、使用全局跳转后main函数中变量的状态

上文已经说明了,使用longjmp会使程序回退到setjmp前的状态。那么,如果main函数中在调用setjmp前定义了一个变量,在调用setjmp后改变了这个变量的值,那么当调用longjmp后,该变量的值是调用setjmp前的还是后的呢?
c标准表示这个状态是不确定的。
如果希望调用longjmp后该变量的值不变,那么可以将该变量定义为全局变量或者使用static修饰,亦或者使用volatile属性声明。

参考资料:

《UNIX环境高级编程(第3版) (史蒂文斯 (W.Richard Stevens) 拉戈 (Stephen A.Rago))
(Z-Library)》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1535481.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

升级VMware

1、vm17pro安装包 VMware Workstation 17 Pro软件下载&#xff1a; 官网下载&#xff1a;Download VMware Workstation Pro 2、点击下一步更改地址 3、注册码 VMware Workstation 17 Pro注册码&#xff1a; 4A4RR-813DK-M81A9-4U35H-06KND 4、打开虚拟机 注&#xff1a; 升…

ip地址数字范围是多少?ip地址四段数字的含义是什么

IP地址&#xff0c;作为互联网上的唯一标识&#xff0c;是由一串数字组成的。这些数字不仅代表了设备的网络位置&#xff0c;还蕴含了丰富的信息。本文将深入探讨IP地址的数字范围以及四段数字的具体含义。 一、IP地址数字范围是多少 IP地址由四段数字组成&#xff0c;每一段数…

JavaEE:文件内容操作(二)

文章目录 文件内容操作读文件(字节流)read介绍read() 使用read(byte[] b) 使用 read(byte[] b, int off, int len) 使用 写文件(字节流)write介绍write(int b) 使用write(byte[] b) 使用write(byte[] b, int off, int len) 使用 读文件(字符流)read() 使用read(char[] cbuf) 使…

基于python+django+vue的鲜花商城系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于pythondjangovueMySQL的线…

如何做系统架构?从动态系统思考的角度

在动态系统思考的背景下&#xff0c;系统架构不再只是一个静态的、结构化的设计&#xff0c;而是一个随着时间推移、基于不同要素互动产生涌现行为的动态过程。系统架构师的任务不仅仅是定义系统的形态和结构&#xff0c;更是通过剖析系统的互动网络、功能涌现和使用场景&#…

UVA1395 Slim Span(最小生成树)

*原题链接*(洛谷) 非常水的一道题。看见让求最小边权差值的生成树&#xff0c;很容易想到kruskal。 一个暴力的想法是以每条边为最小边跑一遍kruskal&#xff0c;然后统计答案。时间复杂度&#xff0c;再看题中很小的数据范围和3s的时限。最后还真就过了。 不过我天真的想了…

三维点云处理(C++)学习记录——PDAL

一、OSGeo4W简概 OSGeo4W是一个基于Windows系统&#xff08;版本7-11&#xff09;的开源地理软件二进制包发布平台。OSGeo4W包括开源GIS桌面应用程序&#xff08;QGIS、GRASS GIS&#xff09;、地理空间库&#xff08;PROJ、GDAL/OGR、GEOS、SpatiaLite、SAGA GIS&#xff09;、…

鸿蒙开发笔记_电商严选02_登录页面跳转到我的页面、并传值

鸿蒙开发笔记整理,方便以后查阅! 由于上班较忙,只能抽空闲暇时间,快速整理更新中。。。 登录页面跳转到我的页面、并传值 效果图 我的设置页面 /*** 我的设置页面*/ import CommonConstants from ./CommonConstants import ItemData from ./ItemData import DataModel fr…

面试官问:你为什么对这个职位感兴趣?

当面试官问到你为什么对某个职位感兴趣时&#xff0c;你的回答应该反映出你对该职位的热情&#xff0c;以及你如何能够为公司带来价值。 重点&#xff1a;在面试前一定要去研究下这家公司&#xff0c;包括他们的团队&#xff0c;文化&#xff0c;产品&#xff0c;服务等各个方…

55 mysql 的登录认证流程

前言 这里我们来看一下 mysql 的认证的流程 我们这里仅仅看 我们最常见的一个 认证的处理流程 我们经常会登录的时候 碰到各种异常信息 认证失败的大体流程 大概的流程是这样 客户端和服务器建立连接之后, 服务器向客户端发送 salt 然后 客户端根据 salt 将客户端传入的…

不同的二叉搜索树

题目 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5示例 2&#xff1a; 输入&#xff1a;n 1 输出&#xff…

运行QWen2-1.5b模型时报错“RuntimeError: cutlassF: no kernel found to launch!”

运行QWen2-1.5b模型时报错“RuntimeError: cutlassF: no kernel found to launch!” #问题&#xff1a;成功加载QWen2-1.5b模型&#xff0c;但是推理时 “model.generate( model_inputs.input_ids, top_pself.top_p, max_new_tokens512 )时”&#xff0c;报错“RuntimeError: …

【吊打面试官系列-Redis面试题】使用过 Redis 做异步队列么,你是怎么用的?

大家好&#xff0c;我是锋哥。今天分享关于【使用过 Redis 做异步队列么&#xff0c;你是怎么用的&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 使用过 Redis 做异步队列么&#xff0c;你是怎么用的&#xff1f; 一般使用 list 结构作为队列&#xff0c;rpus…

关系数据库(1,2)

目录 关系 域 笛卡尔集 元组 分量 基数 码 关系模式 关系模式的表示方式 关系数据库 基本关系操作 完整性 关系 单一的数据结构&#xff0c;二维表是一个逻辑结构&#xff0c;关系模型建立在集合代数的基础上。 域 指具有相同数据类型的集合。 笛卡尔集 笛卡尔集是…

pytorch快速入门(一)—— 基本工具及平台介绍

前言 该pytorch学习笔记应该配合b站小土堆的《pytorch深度学习快速入门教程》使用 环境配置&#xff1a;Anaconda Python编译器&#xff1a;pycharm、jupyter 两大法宝函数 dir&#xff08;&#xff09;&#xff1a;知道包中有什么东西&#xff08;函数 / 属性..…

YOLOv5:TensorRT模型加速与部署(wts版)

视频链接&#xff1a;YOLOv5&#xff1a;TensorRT模型加速与部署&#xff08;wts版&#xff09;_哔哩哔哩_bilibili 《YOLOv5&#xff1a;TensorRT模型加速与部署&#xff08;wts版&#xff09;》课程致力于帮助学生实战YOLOv5目标检测算法的TensorRT加速部署。常心老师将手把…

只需一键,AI Manga Translator 帮你解锁多国语言漫画

只需一键&#xff0c;AI Manga Translator 帮你解锁多国语言漫画 翻译漫画从未如此简单&#xff0c;AI Manga Translator Chrome 扩展程序让你只需点击几下&#xff0c;就能将生肉漫画翻译成你熟悉的语言。本文将带你了解这款工具的基本功能、使用方法&#xff0c;以及为什么你…

方案分享:我是怎么解决一个电力采集问题的?

一、整体解决方案 合宙DTU整体解决方案 DTU硬件&固件SIM卡业务云平台APP&小程序&web h5页面看板&#xff1b; 合宙提供的DTU整体解决方案&#xff0c;核心亮点如下&#xff1a; 品质有保障&#xff0c;硬件DTU固件经过市场上几千家的DTU客户长达5年时间的验证&…

音频芯片DP7344兼容CS4344低成本方案双通道24位DA转换器

产品简介 DP7344 是一款完整的 2 通道输出数模转换芯片&#xff0c;内含插值滤波器、Multi-Bit 数模转换器、输出模拟滤波器&#xff0c;并支持大部分的音频数据格式。 DP7344 基于一个带线性模拟低通滤波器的四阶 Multi-BitΔ∑调制器&#xff0c;自动检测信号频率和主时钟频率…

无人机飞手教员组装、调试高级教学详解

随着无人机技术的飞速发展&#xff0c;其在航拍、农业、救援、监测等多个领域的应用日益广泛&#xff0c;对专业无人机飞手的需求也随之增加。作为无人机飞手教员&#xff0c;掌握无人机的高级组装、调试技能不仅是教学的基础&#xff0c;更是培养学生成为行业精英的关键。本教…