当前位置: 首页 > news >正文

C语言的setjmp和longjmp:可以作异常处理

前言

可以把setjmp和longjmp想象成"设置检查点"和"时空穿越":

  • setjmp就像在游戏里存档,标记一个位置
  • longjmp就像读取存档,直接跳回那个位置

这两个函数主要用在什么场景呢?

  • 错误处理:在深层函数中发生错误时,直接跳回到之前设置的处理点
  • 异常处理:在C语言中模拟类似try-catch的功能
  • 协程实现:保存和恢复执行状态

让我写个简单的例子来说明:

示例1:简单的异常处理

#include <stdio.h>
#include <setjmp.h>

// 定义一个跳转缓冲区,用来保存"存档点"的状态
jmp_buf jump_buffer;

// 模拟一个可能出错的函数
void deep_function(int value) {
    printf("进入 deep_function,参数值:%d\n", value);
    
    if (value < 0) {
        printf("哎呀,发现负数,准备跳回!\n");
        // 跳回到之前设置的点,并带回错误码1
        longjmp(jump_buffer, 1);
    }
    
    printf("deep_function 正常结束\n");
}

int main() {
    printf("程序开始\n");
    
    // setjmp 返回值很特殊:
    // - 第一次调用时返回0
    // - 从longjmp跳回时返回longjmp设置的值
    int ret = setjmp(jump_buffer);
    
    if (ret == 0) {
        printf("设置跳转点\n");
        // 正常执行流程
        deep_function(-1);  // 传入一个负数
        printf("这行不会被执行到\n");
    } else {
        // 从longjmp跳回后的处理
        printf("跳回到跳转点,错误码:%d\n", ret);
    }
    
    printf("程序结束\n");
    return 0;
}

运行结果会是:

程序开始
设置跳转点
进入 deep_function,参数值:-1
哎呀,发现负数,准备跳回!
跳回到跳转点,错误码:1
程序结束

示例2:稍微复杂的异常处理

#include <stdio.h>
#include <setjmp.h>
#include <string.h>

// 定义错误类型
#define ERR_FILE_NOT_FOUND 1
#define ERR_INVALID_DATA   2

// 全局跳转缓冲区
jmp_buf error_jump_buffer;

// 模拟抛出异常
void throw_error(int error_code) {
	longjmp(error_jump_buffer, error_code);
}

// 模拟文件操作
void read_file(const char* filename) {
	printf("尝试读取文件:%s\n", filename);
	
	// 模拟文件不存在
	if (strcmp(filename, "not_exist.txt") == 0) {
		printf("文件不存在!\n");
		throw_error(ERR_FILE_NOT_FOUND);
	}
	
	// 模拟文件数据无效
	if (strcmp(filename, "invalid.txt") == 0) {
		printf("文件数据无效!\n");
		throw_error(ERR_INVALID_DATA);
	}
	
	printf("文件读取成功\n");
}

// 模拟处理文件
void process_file(const char* filename) {
	printf("\n开始处理文件:%s\n", filename);
	
	// 设置错误处理点
	int error_code = setjmp(error_jump_buffer);
	
	if (error_code == 0) {
		// 正常执行流程
		read_file(filename);
		printf("文件处理完成\n");
	} else {
		// 错误处理
		switch (error_code) {
		case ERR_FILE_NOT_FOUND:
			printf("错误处理:文件未找到\n");
			break;
		case ERR_INVALID_DATA:
			printf("错误处理:无效数据\n");
			break;
			default:
				printf("错误处理:未知错误 %d\n", error_code);
		}
	}
}

int main() {
	// 测试不同情况
	process_file("normal.txt");      // 正常文件
	process_file("not_exist.txt");   // 不存在的文件
	process_file("invalid.txt");     // 无效数据的文件
	
	return 0;
}

总结:

需要注意的几点:

使用限制:

  • setjmp必须在longjmp之前调用
  • longjmp不能跳转到已经返回的函数
  • 局部变量在longjmp后的值是不确定的(除非声明为volatile)

潜在风险:

  • 过度使用会使程序流程难以理解
  • 可能导致资源泄露(因为跳过了正常的清理代码)
  • 不能跨线程使用

最佳实践:

  • 主要用于错误处理
  • 尽量在较小的范围内使用
  • 确保正确处理资源清理
  • 现代C++程序应该使用异常处理机制

相关文章:

  • 《算法笔记》9.3小节——数据结构专题(2)->树的遍历 问题 B: 树的高度
  • VSCode创建VUE项目(四)增加用户Session管理
  • 常⻅CMS漏洞之一:WordPress
  • 【C++】priority_queue的使用及模拟实现(含仿函数介绍)
  • v-form标签里的:rules有什么作用。如何定义。
  • Microsoft Edge浏览器的取证分析(基于Chromium)
  • CSGHub开源版本v1.5.0更新
  • Vulnhub靶场matrix-breakout-2-morpheus攻略
  • 在springboot3.x中使用Ehcache3.x
  • 网络编程之客户端通过服务器与另外一个客户端交流
  • oracle删除表中重复数据
  • 正则表达式与拓展正则简单理解
  • LeetCode[93] 复原 IP 地址
  • Mimikyu综合靶场训练
  • 大数据学习(74)-Hue元数据
  • Python标准库之os模块常用方法
  • Excel Script Lab学习笔记
  • Pytorch使用手册(专题五十)—自定义运算符
  • 《Python深度学习》第三讲:神经网络
  • sqlite mmap
  • .com网站备案/最新军事报道
  • 百度推广网站吸引力/江苏百度推广代理商
  • qq群引流推广网站/邵阳seo优化
  • 好的手机网站推荐/html简单网页代码
  • 四字母net做网站怎么样/百度链接提交入口
  • 泉州市城乡和建设网站/百度云官网