c语言中setjmp与longjmp(1)

Linux(31)Rockchip RK3568 Ubuntu22.04上部署 Docker: 问题与解决方案 本博客在总结这些问题及其解决方案,为遇到类似问题的兄弟提供参考,如果我后续有碰到其他Docker 问题也会在此更新补充。 阅读详情

setjmp函数与longjmp函数总是组合起来使用,它们是紧密相关的一对操作,只有将它们结合起来使用,才能达到程序控制流有效转移的目的,才能按照程序员的预先设计的意图,去实现对程序中可能出现的异常进行集中处理。

与goto语句的作用类似,它能实现本地的跳转

这种情况容易理解,不过还是列举出一个示例程序吧!如下:

void main( void )
{
int jmpret;

jmpret = setjmp( mark );
if( jmpret == 0 )
{
// 其它代码的执行
// 判断程序远行中,是否出现错误,如果有错误,则跳转!
if(1) longjmp(mark, 1);

// 其它代码的执行
// 判断程序远行中,是否出现错误,如果有错误,则跳转!
if(2) longjmp(mark, 2);

// 其它代码的执行
// 判断程序远行中,是否出现错误,如果有错误,则跳转!
if(-1) longjmp(mark, -1);

// 其它代码的执行
}
else
{
// 错误处理模块
switch (jmpret)
{
case 1:
printf( "Error 1/n");
break;
case 2:
printf( "Error 2/n");
break;
case 3:
printf( "Error 3/n");
break;
default :
printf( "Unknown Error");
break;
}
exit(0);
}

return;
}

  上面的例程非常地简单,其中程序中使用到了异常处理的机制,这使得程序的代码非常紧凑、清晰,易于理解。在程序运行过程中,当异常情况出现后,控制流是进行了一个本地跳转(进入到异常处理的代码模块,是在同一个函数的内部),这种情况其实也可以用goto语句来予以很好的实现,但是,显然setjmp与 longjmp的方式,更为严谨一些,也更为友善。程序的执行流如图17-1所示。

setjmp与longjmp相结合,实现程序的非本地的跳转

  呵呵!这就是goto语句所不能实现的。也正因为如此,所以才说在C语言中,setjmp与longjmp相结合的方式,它提供了真正意义上的异常处理机制。其实上一篇文章中的那个例程,已经演示了longjmp函数的非本地跳转的场景。这里为了更清晰演示本地跳转与非本地跳转,这两者之间的区别,我们在上面刚才的那个例程基础上,进行很小的一点改动,代码如下:

void Func1()
{
// 其它代码的执行
// 判断程序远行中,是否出现错误,如果有错误,则跳转!
if(1) longjmp(mark, 1);
}

void Func2()
{
// 其它代码的执行
// 判断程序远行中,是否出现错误,如果有错误,则跳转!
if(2) longjmp(mark, 2);
}

void Func3()
{
// 其它代码的执行
// 判断程序远行中,是否出现错误,如果有错误,则跳转!
if(-1) longjmp(mark, -1);
}

void main( void )
{
int jmpret;

jmpret = setjmp( mark );
if( jmpret == 0 )
{
// 其它代码的执行

// 下面的这些函数执行过程中,有可能出现异常
Func1();

Func2();

Func3();

// 其它代码的执行
}
else
{
// 错误处理模块
switch (jmpret)
{
case 1:
printf( "Error 1/n");
break;
case 2:
printf( "Error 2/n");
break;
case 3:
printf( "Error 3/n");
break;
default :
printf( "Unknown Error");
break;
}
exit(0);
}

return;
}

  回顾一下,这与C++中提供的异常处理模型是不是很相近。异常的传递是可以跨越一个或多个函数。这的确为C程序员提供了一种较完善的异常处理编程的机制或手段。

setjmp和longjmp使用时,需要特别注意的事情

1、setjmp与longjmp结合使用时,它们必须有严格的先后执行顺序,也即先调用setjmp函数,之后再调用longjmp函数,以恢复到先前被保存的“程序执行点”。否则,如果在setjmp调用之前,执行longjmp函数,将导致程序的执行流变的不可预测,很容易导致程序崩溃而退出。请看示例程序,代码如下:

class Test
{
public:
Test()
~Test()
}obj;

//注意,上面声明了一个全局变量obj

void main( void )
{
int jmpret;

// 注意,这里将会导致程序崩溃,无条件退出
Func1();
while(1);

jmpret = setjmp( mark );
if( jmpret == 0 )
{
// 其它代码的执行

// 下面的这些函数执行过程中,有可能出现异常
Func1();

Func2();

Func3();

// 其它代码的执行
}
else
{
// 错误处理模块
switch (jmpret)
{
case 1:
printf( "Error 1/n");
break;
case 2:
printf( "Error 2/n");
break;
case 3:
printf( "Error 3/n");
break;
default :
printf( "Unknown Error");
break;
}
exit(0);
}

return;
}

  上面的程序运行结果,如下:
  构造对象
  Press any key to continue

  的确,上面程序崩溃了,由于在Func1()函数内,调用了longjmp,但此时程序还没有调用setjmp来保存一个程序执行点。因此,程序的执行流变的不可预测。这样导致的程序后果是非常严重的,例如说,上面的程序中,有一个对象被构造了,但程序崩溃退出时,它的析构函数并没有被系统来调用,得以清除一些必要的资源。所以这样的程序是非常危险的。

  2、除了要求先调用setjmp函数,之后再调用longjmp函数(也即longjmp必须有对应的setjmp函数)之外。另外,还有一个很重要的规则,那就是longjmp的调用是有一定域范围要求的。这未免太抽象了,还是先看一个示例,如下:

int Sub_Func()
{
int jmpret, be_modify;

be_modify = 0;

jmpret = setjmp( mark );
if( jmpret == 0 )
{
// 其它代码的执行
}
else
{
// 错误处理模块
switch (jmpret)
{
case 1:
printf( "Error 1/n");
break;
case 2:
printf( "Error 2/n");
break;
case 3:
printf( "Error 3/n");
break;
default :
printf( "Unknown Error");
break;
}

//注意这一语句,程序有条件地退出
if (be_modify==0) exit(0);
}

return jmpret;
}

void main( void )
{
Sub_Func();

// 注意,虽然longjmp的调用是在setjmp之后,但是它超出了setjmp的作用范围。
longjmp(mark, 1);
}

  如果你运行或调试(单步跟踪)一下上面程序,发现它真是挺神奇的,居然longjmp执行时,程序还能够返回到setjmp的执行点,程序正常退出。但是这就说明了上面的这个例程的没有问题吗?我们对这个程序小改一下,如下:

int Sub_Func()
{
// 注意,这里改动了一点
int be_modify, jmpret;

be_modify = 0;

jmpret = setjmp( mark );
if( jmpret == 0 )
{
// 其它代码的执行
}
else
{
// 错误处理模块
switch (jmpret)
{
case 1:
printf( "Error 1/n");
break;
case 2:
printf( "Error 2/n");
break;
case 3:
printf( "Error 3/n");
break;
default :
printf( "Unknown Error");
break;
}

//注意这一语句,程序有条件地退出
if (be_modify==0) exit(0);
}

return jmpret;
}

void main( void )
{
Sub_Func();

// 注意,虽然longjmp的调用是在setjmp之后,但是它超出了setjmp的作用范围。
longjmp(mark, 1);
}

  运行或调试(单步跟踪)上面的程序,发现它崩溃了,为什么?这就是因为,“在调用setjmp的函数返回之前,调用longjmp,否则结果不可预料” (这在上一篇文章中已经提到过,MSDN中做了特别的说明)。为什么这样做会导致不可预料?其实仔细想想,原因也很简单,那就是因为,当setjmp函数调用时,它保存的程序执行点环境,只应该在当前的函数作用域以内(或以后)才会有效。如果函数返回到了上层(或更上层)的函数环境中,那么setjmp保存的程序的环境也将会无效,因为堆栈中的数据此时将可能发生覆盖,所以当然会导致不可预料的执行后果。

    这里在vc下运行上面第一个真的没有问题,可是第二个有问题,在linux下用gcc编译,两个代码都有问题,不知道为什么?还要再试验下。。

   3、不要假象寄存器类型的变量将总会保持不变。在调用longjmp之后,通过setjmp所返回的控制流中,例程中寄存器类型的变量将不会被恢复。(MSDN中做了特别的说明,上一篇文章中,这也已经提到过)。寄存器类型的变量,是指为了提高程序的运行效率,变量不被保存在内存中,而是直接被保存在寄存器中。寄存器类型的变量一般都是临时变量,在C语言中,通过register定义,或直接嵌入汇编代码的程序。这种类型的变量一般很少采用,所以在使用setjmp和longjmp时,基本上不用考虑到这一点。

  4、MSDN中还做了特别的说明,“在C+ +程序中,小心对setjmp和longjmp的使用,因为setjmp和longjmp并不能很好地支持C++中面向对象的语义。因此在C++程序中,使用C++提供的异常处理机制将会更加安全。”虽然说C++能非常好的兼容C,但是这并非是100%的完全兼容。例如,这里就是一个很好的例子,在C++ 程序中,它不能很好地与setjmp和longjmp和平共处。在后面的一些文章中,有关专门讨论C++如何兼容支持C语言中的异常处理机制时,会做详细深入的研究,这里暂且跳过。

《四》:LBE,VR 大空间系列——Pico的空间扫描方式 (这里有个选项叫高精度扫描模式,这个功能在下方详细补充)系统会根据绘制的顶点,将区域分割成若干个4X4米的小方格,我们只需要根据提示,首先进入一个方格子空间内部,然后依次凝视每个区域上下左右前后六个面的小方格组,每一面4个,直至全部消失, 消失后地面会出现一个方形行走路径,我们沿着边缘正或反走一圈即可,完成后此块区域即自动消失。不过由于pico有一个高精度扫描圈,如图加粗的圆环,这个圆环的意思是在在内部的区域扫描精度较高,越远离原点的区域误差越大,所以为了更有效的利用,建议原点设置在场地中心区域。 阅读详情

相关推荐

视频预处理--经典方法卷积3D

在三维卷积操作中,卷积核不仅在空间维度上滑动,还在时间维度上滑动,从而同时捕捉时间和空间上的特征。通过合理设置步长和填充,可以灵活控制输出特征图的大小和特征提取的效果。你的理解非常准确:三维卷积核就像是一个长度为 3 的滑动窗口,每次选取 3 个连续的帧进行卷积操作,而步长和填充则进一步优化了这一过程。

m0_73359068的博客 1649

C语言中setjmp函数和longjmp函数

setjmp和longjmp的使用

wjp1792342241的博客 1227

你的Wi-Fi总断网?可能是DHCP租约到期惹的祸!手把手教你用Windows/路由器设置永久IP或延长租期

本文深入解析家庭Wi-Fi频繁断网的常见原因——DHCP租约到期问题,并提供Windows和路由器设置永久IP或延长租期的详细教程。通过对比静态IP配置与延长租期两种方案,帮助用户有效解决网络不稳定问题,特别适合游戏玩家和远程工作者优化家庭网络环境。

weixin_29305313的博客 1430

【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现

一、转移表 二、回调函数是什么? 三、qsort函数细解 3.1 类比冒泡排序? 3.2 qosrt函数超详解 3.2.1qsort函数排序整型数据 3.2.2 使⽤qsort排序结构数据 四、 qsort函数的模拟实现 4.1 模拟qsort整形数据 4.2 模拟`qsort`排序结构数据

a_sen的博客 1629

Zemax:初学者的混合模式

光线以序列模式开始,然后接近非序列组件的入口端口。到达入口端口后,光线以非序列模式传播,然后接近出口端口。光线离开出口端口后,我们又回到序列模式。在此博客中,使用混合模式的示例将演示根据您自己的需要复制此工作流程所需的基本设置,以及一些有用的技巧。非序列组件表面类型必须在序列模式和非序列模式下定义。为了定义非序列组件的几何形状,请转到设置->编辑器->非序列,单击非序列编辑器。一旦我们进入非序列组件编辑器:表面 2 上的组件组,找到一个对象类型并进行定义。它能让您兼具序列模式的精确性和非序列模式的灵活性。

jkh920184196的博客 1341

保姆级教程:在K230开发板上为张大头步进电机实现位置、速度、回零全功能控制

本文提供了一份详细的K230开发板与张大头步进电机的控制教程,涵盖硬件连接、协议解析、模块化代码实现及实战案例。通过位置、速度和回零功能的全面讲解,帮助开发者快速掌握步进电机的高级控制技术,适用于自动化、机器人等应用场景。

weixin_42629671的博客 712

setjmp 和 longjmp 函数

成员函数 int setjmp(jmp_buf env) 创建本地的jmp_buf缓冲区并且初始化,用于将来跳转回此处。这个子程序[1] 保存程序的调用环境于env参数所指的缓冲区,env将被longjmp使用。如果是从setjmp直接调用返回,setjmp返回值

sgling0440的专栏 626

实战指南:轻松破解DataDome滑块验证码的关键步骤

本文详细介绍了破解DataDome滑块验证码的关键步骤,包括理解其工作原理、准备工作、参数获取与配置、完整破解流程及API调用。通过使用Capsolver服务和模拟真实用户行为,帮助开发者有效绕过这一反机器人机制,同时强调了法律与道德考量。

weixin_30415113的博客 481

gcc都做了什么优化

直接上程序: setjmp和longjmp是处理函数嵌套调用的,goto语句不能跨越函数,所以不选择goto。 #include <setjmp.h> int setjmp(jmp_buf env); //返回值:若第一次直接调用则直接返回0,若从longjmp调用则返回下面的val void longjmp(jmp_buf env, int val); ...

weixin_30463341的博客 96

DSP28335新手避坑指南:手把手教你用CCS6.2生成10KHz SPWM(附完整工程)

本文详细介绍了如何使用DSP28335开发板和CCS6.2环境生成10KHz SPWM波形的完整工程指南。从开发环境配置、ePWM模块设置到SPWM算法实现,特别针对新手常见问题提供了解决方案和调试技巧,帮助工程师快速掌握DSP28335的SPWM生成技术。

weixin_42522374的博客 182

HTOL集成电路老化测试学习总结-20250510

电子元器件的可靠性在产品开发中至关重要,尤其是在微电子技术迅速发展的今天。电子元器件的失效率通常遵循“浴盆曲线”,分为早期失效期、可使用期和老化期。为了评估芯片的可靠性,常采用高温操作寿命测试(HTOL),通过高温和高压加速芯片老化,以筛选出早期失效的芯片并评估其长期可靠性。HTOL测试中,芯片在高温下运行并监控其性能变化,通过阿伦尼乌斯公式计算加速因子,预测芯片的失效率和寿命。此外,Burn-in测试用于加速芯片老化,提前发现并剔除不合格产品,而早期失效率测试(ELFR)则用于评估产品初期使用阶段的可靠性

歌颂苦难的行为是无耻的; 2103

非局部跳转函数 setjmp 和 longjmp 介绍

C 语言中的 goto 语句是不能跨越函数的,属于局部性跳转,若要执行跨函数跳转,可使用 setjmp 和 longjmp 函数,它们对于处理发生在很深层嵌套函数调用中的出错情况时非常有用。 [code="C"] #include int setjmp(jmp_buf env); /* 返回值:若直接调用,返回 0;若从 longjmp 返...

aisxyz 233

华为OD干了两个月,还是跑了

​本人工作了快13年,base南京。2024年2月份由于公司业务变动第一次拿到了公司发的大礼包,同时也面临着失业的问题,我对自己的技术还是很有信心的,但是,找了大概有一个多月时间,发现心意的工作的确不太好找,当然收到挺多家offer,就是薪资不太满意,外包也一直不想去,不过说实话外包给的薪资普遍要比自研的单位要高一些,最后为了钱还是进华为(既然选择外包那就选择好一些的吧),毕竟中年老男人工作不能断太久。

啊渊的专栏 1万+

C语言中setjmp和longjmp使用细节1

最近在拜读《C专家编程》的时候遇到setjmp和longjmp,由于个人资质的问题所以对于书上的某些例子和解释有些不解,解开迷惑之后,记录于此。 引用文献:《C专家编程》P128 文中有这样的一个举例: 存在的疑问是为什么会打印出back in main字符串。 我个人做了如下测试: 在main函数中定义了一个变量A=setjmp(buf); if语句改为 if(A){...}

行者 1444

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

C语言跳转语句(break语句,continue语句,goto语句,return语句,跳转函数setjmp和longjmp)_c语言 跳转(1)

/ 非法: 从arr的作用域外跳转到作用域内。// 如果没有错误,程序会执行到此处。// 合法:在arr的作用域内跳转。// 一个变长度数组。#include // 定义布尔值,true和false(C99)error_exit: // 错误处理子程序。// 抛弃这个值,并读取另一个值。// 已存储的数据个数加1。// 已存储的数据个数。// 已存储的数据个数。// 返回两个整数类型参数中的较小值。// 在函数内部处理错误。

2401_84973528的博客 461

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

测试 setjmp 和 longjmp 的用法

C语言goto是不能跨函数的, 原因: 跨函数需要保存现场, 回来需要恢复现场. setjmp 和 longjmp 配合, 可以实现在C语言程序中跨函数跳转. M$给的例子, 对于测试setjmp和longjmp整的复杂了. 我写了一个简单明了的测试程序, 只测试 setjmp和longjmp. /// @file ClassroomExamples.c /// @brief xx

博客标题不能为空 815

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

setjmp

【代码】setjmp。

bigfanofloT的博客 317

linux程序 报浮点异常,linux c语言编程,使用setjmp和longjmp函数自制类似python的try-catch模块捕获异常,处理段错误,浮点错误等信号错误(1)...

程序的非逻辑错误程序出错大体可以分两种,一种是出错时,程序不会退出,可以继续往下执行,例如 open 文件失败,也只是无法打开文件而已,程序还可以执行我们设定的错误处理语句,比如打印出错误信息等。还有一种错误发生时,程序直接就退出了,例如非法操作指针引起的段错误,把 0 做被除数的浮点错误等。先来看一段 c 代码,代码很简单,就是计算 8 除以 0 的值,传递给 a。显然,任何数除以 0 都是无法...

weixin_28730403的博客 389

C中的try-catch

之前看lua源码,看到LUAI_TRY没当回事,以为就是直接调用。 今天细细调查后发现还真是学到了新玩意儿。照猫画瓢写了一个小例子。 费话不多说,show you the code. #include <stdio.h> #include <setjmp.h> #define DECLARE_TRY_CATCH() jmp_buf gJmpBuf; int gSetjmpRet = 0 #define TRY(foo) if((gSetjmpRet = setjmp(gJmpB

dcw0402的专栏 512

c 语言中的setjmp和longjmp

此文是学习 C专家编程 中的笔记。 setjmp和longjmp是C语言所独有的,它们部分弥补了C语言有限的转移能力。 函数说明(来自wiki百科): int setjmp(jmp_buf env) 建立本地的jmp_buf缓冲区并且初始化,用于将来跳转回此处。这个子程序保存程序的调用环境于env参数所指的缓冲区,env将被longjmp使用。如果是从setjmp直接调用返

huhuhaha008的专栏 579

C 语言中 setjmp 和 longjmp

在 C 语言中,我们不能使用 goto 语句来跳转到另一个函数中的某个 label 处;但提供了两个函数——setjmp 和 longjmp来完成这种类型的分支跳转。后面我们会看到这两个函数在处理异常上面的非常有用。 setjmp 和 longjmp 使用方法 我们都知道要想在一个函数内进行跳转,可以使用 goto 语句(不知怎么该语句在中国学生眼中就是臭名昭著,几乎所有国内教材都一刀

海风林影 1683

C语言中的setjmp和longjmp

在C语言中,goto语句只能在一个函数内实现跳转,而不能在函数间进行跳转。如果希望在函数间跳转,可以使用 setjmp 和 longjmp 函数。 Linux 会把进程的上下文保存在 task_struct 结构体中,切换时直接恢复。而 setjmp 和 longjmp 的原理也差不多: 第一次调用setjmp时,保存该函数内的上下文;调用longjmp时,跳转到setjmp处再调用setjmp来...

FinixLei的专栏 (https://github.com/FinixLei) 1503

setjmp和longjmp

此文是学习 C专家编程 中的笔记。 setjmp和longjmp是C语言所独有的,它们部分弥补了C语言有限的转移能力。 函数说明(来自wiki百科): int setjmp(jmp_buf env) 建立本地的jmp_buf缓冲区并且初始化,用于将来跳转回此处。这个子程序保存程序的调用环境于env参数所指的缓冲区,env将被longjmp使用。如果是从setjmp直接调用返

cscmaker的专栏 6206

Emscripten - C setjmp-longjmp 支持

Emscripten支持setjmp-longjmp功能,提供两种实现方式:基于JavaScript的模拟和基于WebAssembly异常处理的实现。默认根据异常模式自动选择,也可通过SUPPORT_LONGJMP参数手动配置。JavaScript方式兼容性好但体积较大,Wasm方式性能更好但需要浏览器支持新特性。使用时有特殊限制:不支持间接调用setjmp,且在使用Wasm异常时不能在catch块中直接调用setjmp。该功能设计为与Emscripten的异常处理机制协同工作,建议采用统一的实现方式。

1000

c语言的setjmp和longjmp

    在移植jpglib后,发现当jpeg文件遭到破坏后,解码器内部就会调用默认的错误处理函数,但此函数实际上并    没有真正处理错误,而只简单地做了资源释放,然后调用exit()函数.此函数对于windows的application来说,就是简单的结束进程.可是对于嵌入式设备来说根本没有exit()函数.METHODDEF(int)error_exit (j_common_ptr cinfo

zhongyh的专栏 3201

C语言 - setjmp与longjmp

全面了解setjmp与longjmp(C语言异常处理机制) http://home.lupaworld.com/index.php/home/home-space-uid-32446-do-blog-id-131450.html 为了更好地、更方便地支持异常处理编程...

488
上一篇: 讲讲volatile的作用
下一篇: c语言中setjmp与longjmp(2)
骑行的蜗牛
博客等级 码龄21年 107粉丝 86原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值