程序的非正常跳转

 

我们一般在程序中执行的跳转可以通过 goto while for if 等来实现。但是这些跳转都局限在函数内部,也就是说是一种 non-local goto ”, 不能在执行环境中进行任意的跳转。幸运的是绝大多数编译器还支持另外两个函数: setjmp longjmp 。原型如下:

 

int setjmp( jmp_buf env );

void longjmp( jmp_buf env , int value );

setjmp 保存当前执行环境下的栈。根据具体的情况,函数的返回值有两种情况。第一种情况:函数保存当前执行环境下的栈时,其返回值为 0 。第二种情况:函数的返回值由 longjmp 的第二个参数决定。然而,如果 longjmp 的第二个参数为 0 时,函数的返回值是 1

longjmp setjmp 保存下来的栈,恢复程序在执行到 setjmp 时的状态,然后程序的执行路径直接跳到 setjmp 之后。注意: setjmp 任然被执行,但是返回值将由 longjmp 的第二个参数来决定。

下面的代码是摘录自 MSDN 的一个例子程序,简要的说明了这两个函数的用法。

/* FPRESET.C: This program uses signal to set up a

  * routine for handling floating-point errors.

  */

 

#include <stdio.h>

#include <signal.h>

#include <setjmp.h>

#include <stdlib.h>

#include <float.h>

#include <math.h>

#include <string.h>

 

jmp_buf mark;              /* Address for long jump to jump to */

int     fperr;             /* Global error number */

 

void __cdecl fphandler( int sig, int num );   /* Prototypes */

void fpcheck( void );

 

void main( void )

{

       double n1, n2, r;

       int jmpret;

 

       /* Unmask all floating-point exceptions. */

    _control87( 0, _MCW_EM );

       /* Set up floating-point error handler. The compiler

    * will generate a warning because it expects

    * signal-handling functions to take only one argument.

    */

    if( signal( SIGFPE, fphandler ) == SIG_ERR )

             

       {

              fprintf( stderr, "Couldn't set SIGFPE/n" );

              abort();   }

      

              /* Save stack environment for return in case of error. First

              * time through, jmpret is 0, so true conditional is executed.

              * If an error occurs, jmpret will be set to -1 and false

              * conditional will be executed.

    */

       jmpret = setjmp( mark );

 

       if( jmpret == 0 )

       {

              printf( "Test for invalid operation - " );

              printf( "enter two numbers: " );

              scanf( "%lf %lf", &n1, &n2 );

              r = n1 / n2;

              /* This won't be reached if error occurs. */

              printf( "/n/n%4.3g / %4.3g = %4.3g/n", n1, n2, r );

             

              r = n1 * n2;

              /* This won't be reached if error occurs. */

              printf( "/n/n%4.3g * %4.3g = %4.3g/n", n1, n2, r );

       }

       else

              fpcheck();

}

 

 

 

/* fphandler handles SIGFPE (floating-point error) interrupt. Note

  * that this prototype accepts two arguments and that the

  * prototype for signal in the run-time library expects a signal

  * handler to have only one argument.

  *

  * The second argument in this signal handler allows processing of

  * _FPE_INVALID, _FPE_OVERFLOW, _FPE_UNDERFLOW, and

  * _FPE_ZERODIVIDE, all of which are Microsoft-specific symbols

  * that augment the information provided by SIGFPE. The compiler

  * will generate a warning, which is harmless and expected.

 

  */

void fphandler( int sig, int num )

{

   /* Set global for outside check since we don't want

    * to do I/O in the handler.

    */

   fperr = num;

   /* Initialize floating-point package. */

   _fpreset();

   /* Restore calling environment and jump back to setjmp. Return

    * -1 so that setjmp will return false for conditional test.

    */

   longjmp( mark, 0 );

}

 

 

void fpcheck( void )

{

   char fpstr[30];

   switch( fperr )

   {

   case _FPE_INVALID:

       strcpy( fpstr, "Invalid number" );

       break;

   case _FPE_OVERFLOW:

       strcpy( fpstr, "Overflow" );

 

       break;

   case _FPE_UNDERFLOW:

       strcpy( fpstr, "Underflow" );

       break;

   case _FPE_ZERODIVIDE:

       strcpy( fpstr, "Divide by zero" );

       break;

   default:

       strcpy( fpstr, "Other floating point error" );

       break;

   }

   printf( "Error %d: %s/n", fperr, fpstr );

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值