zoukankan      html  css  js  c++  java
  • (转载)setjmp与longjmp

    (转载)http://blog.csdn.net/stephen_yin/article/details/6645072

    setjmp和longjmp是C语言独有的,只有将它们结合起来使用,才能达到程序控制流有效转移的目的,按照程序员的预先设计的意图,去实现对程序中可能出现的异常进行集中处理。

    先来看一下这两个函数的定义吧:

    setjmp和longjmp的函数原型在setjmp.h中

    函数原型:

    int setjmp(jmp_buf envbuf);

    setjmp函数用缓冲区envbuf保存系统堆栈的内容,以便后续的longjmp函数使用。setjmp函数初次启用时返回0值。

     

    void longjmp(jmp_buf envbuf, int val);

    longjmp函数中的参数envbuf是由setjmp函数所保存的堆栈环境,参数val设置setjmp函数的返回值。longjmp函数本身是没有返回值的,它执行后跳转到保存envbuf参数的setjmp函数调用,并由setjmp函数调用返回,此时setjmp函数的返回值就是val。

     

    上面的说明有点拗口,通俗的解释是:先调用setjmp,用变量envbuf记录当前的位置,然后调用longjmp,返回envbuf所记录的位置,并使setjmp的返回值为val。当时用longjmp时,envbuf的内容被销毁了。其实这里的“位置”一词真正的含义是栈定指针。

     

    接着让我们看一个小例子吧:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <setjmp.h>
    
    jmp_buf buf;
    
    void banana(void)
    {
        printf("in banana()\n");
        longjmp(buf, 27);
    
        printf("you'll never see this, because i longjmp'd\n");
    }
    
    int main(int argc, char* argv[])
    {
        int ret;
    
        if (ret = setjmp(buf))
        {
            printf("The if ret:%d\n", ret);
            printf("back in main\n");
        }
        else
        {
            printf("The else ret:%d\n", ret);
            printf("first time through\n");
            banana();
        }
    
        return 0;
    }

    (代码段引自《C专家编程》:p)

    程序输出:

    The else ret:0
    first time through
    in banana()
    The if ret:27
    back in main

    (1)“神奇”函数setjmp()会产生“两个返回值”,第一个 返回值始终为0。

    (2)还可以看到“神奇”函数setjmp()使if...else这“两个分支都执行”了。

     

    setjmp/longjmp的最大用处是错误恢复,类似try ...catch...

    他们的功能比goto强多了,goto只能在函数体内跳来跳去,而setjmp/longjmp可以在到过的所有位置间。

     

    从java、.net世界来的兄弟们也许会很不屑于这对函数,也许会觉得这样的功能会使代码的可读性变差。不过请别忘了,这里是C的世界,每个世界有每个世界的哲学,OO只是方法学的一种,而不是全部。quake3是用C写的,据看过其代码的前辈说,其模块化非常好,所以这也是我看quake3代码的初衷。(哦,算了吧,写游戏不是随便说说的...)

    注:

       我第一次看到setjmp是在quake3代码的Com_Init中,

    /* 
    ================= 
    Com_Init 
    ================= 
    */ 
    void Com_Init( char *commandLine ) { 
        char    *s;

        Com_Printf( "%s %s %s\n", Q3_VERSION, CPUSTRING, __DATE__ );

        if ( setjmp (abortframe) ) { 
            Sys_Error ("Error during initialization"); 
        }

    ....

    卡马克在这里也是当catch用的,其中的一句注释是这么写的:

    jmp_buf abortframe;        // an ERR_DROP occured, exit the entire frame

  • 相关阅读:
    NTP on FreeBSD 12.1
    Set proxy server on FreeBSD 12.1
    win32 disk imager使用后u盘容量恢复
    How to install Google Chrome Browser on Kali Linux
    Set NTP Service and timezone on Kali Linux
    Set static IP address and DNS on FreeBSD
    github博客标题显示不了可能是标题包含 特殊符号比如 : (冒号)
    server certificate verification failed. CAfile: none CRLfile: none
    删除文件和目录(彻底的)
    如何在Curl中使用Socks5代理
  • 原文地址:https://www.cnblogs.com/Robotke1/p/3058597.html
Copyright © 2011-2022 走看看