• setjmp与longjmp


    在C中有时我们会使用goto语句用于运行跳转,可是不能跨越函数

    #include <stdio.h>
    
    void func2()
    {
    	int num = 0;
    dst2:
    	if (num > 0)
    	{	
    		printf("func1()
    ");
    		func3();
    	}
    	if (num == 1)
    		return;
    	num++;
    	goto dst2;
    }
    
    void func3()
    {
    }
    
    void func1()
    {
    dst1:
    	func2();
    	goto dst2;//error
    }
    
    int main()
    {
    	func1();	
    	return 0;
    }
    

    而在深层嵌套函数中的跳转,能够使用setjmp和longjmp函数。
    这两个函数对于处理发生在深层嵌套函数中出错的情况是很实用的。

    函数原型:

    #include <setjmp.h>
    int setjmp(jmp_buf env);
    	返回值:若直接调用则返回0,若从longjmp调用返回则返回非0值
    void longjmp(jmp_buf env, int val);
    參数说明:
    setjmp的env參数的类型是一个特殊类型jmp_buf,这一数据类型是某种形式的数组,当中存放存放在调用longjmp时能用来恢复栈状态的全部信息
    longjmp的env參数指定恢复栈到某个状态,val为非0值,使用第二个參数的原因是对于一个setjmp能够有多个longjmp。比如。在func2()中以val为2调用longjmp,
    func3()以val3调用longjmp,调用longjmp导致程序跳转到对应的指定env处的setjmp.并导致setjmp返回val值。通过測试返回值可推断造成返回的longjmp是在func2()中还是func3()中

    实例:

    #include <stdio.h>
    #include <setjmp.h>
    
    jmp_buf jmpbuffer;
    int times = 0;
    
    void func3()
    {
    	times++;
    	longjmp(jmpbuffer, 3);
    }
    
    void func2()
    {
    	func3();
    }
    
    void func1()
    {
    	int r;
    	r = setjmp(jmpbuffer);
    	printf("%d
    ", r);
    	if (times == 1)
    		return;
    	func2();
    }
    
    int main()
    {
    	func1();	
    	return 0;
    }
    

    longjmp跳转对变量的影响
    longjmp实际上恢复栈的状态。所以我们能够猜測,对于全局变量和静态变量。不存储在栈区中,所以值不会受影响,而大多数实现不会回滚自己主动变量的值
    若不希望自己主动变量的值被回滚,能够指定其具有volatile属性。

    很多其它关于volatile见  http://blog.csdn.net/aspnet_lyc/article/details/17231989

    实例:

    #include <stdio.h>
    #include <setjmp.h>
    #include <stdlib.h>
    
    jmp_buf jmpbuffer;
    
    void func1()
    {
    	int auto_data = 0;
    	static int static_data = 0;
    	volatile int volatile_data = 0;
    	
    	if (setjmp(jmpbuffer) != 0)
    	{
    		printf("after jmp:
    ");
    		printf("auto: %d
    ", auto_data);
    		printf("static: %d
    ", static_data);
    		printf("volatile: %d
    ", volatile_data);
    		exit(0);
    	}
    	printf("auto: %d
    ", auto_data);
    	printf("static: %d
    ", static_data);
    	printf("volatile: %d
    ", volatile_data);
    	
    	auto_data++;
    	static_data++;
    	volatile_data++;
    	longjmp(jmpbuffer, 3);
    }
    
    int main()
    {
    	func1();	
    	return 0;
    }

    以不带优化和带优化选项对此程序部分进行编译,运行结果:

    不带优化编译gcc


    带优化编译 gcc -O


    存放在存储器中的变量将具有longjmp时的值,而在cpu寄存器中的变量则恢复为调用setjmp时的值。
    不进行优化时,自己主动变量存放在存储器中。
    优化后,自己主动变量存放寄存器中,这就是优化编译后auto_data值变为0的原因。



  • 相关阅读:
    vue 数字滚动的插件 vue-count-to
    ASP.NET Core EF 查询获取导航属性值,使用Include封装
    nginx在asp.net mvc项目中 配置 初步快速入门
    JQuery EasyUI 扩展方法 日期控件 设置时间段函数
    JQueryEasyUI easyui-combobox 单击文本区域显示下拉菜单
    Jquery Easy UI Datagrid 上下移动批量保存数据
    ASP.NET MVC BundleConfig介绍和使用
    ASP.NET MVC5 视图相关学习
    SqlDependency数据库同步+signalr 推送消息
    T4 模板自动生成带注释的实体类文件
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/6742404.html
Copyright © 2020-2023  润新知