Use setjmp and longjmp for exception handling in C Language

Source: Internet
Author: User

Use setjmp and longjmp for exception handling in C Language

Error handling is a problem that must be solved in any language. If 100% of the Error Code cannot be correctly executed, a mechanism for error handling is required. Exception Handling is one of the error handling methods.

1. Active Record)

Every time a function is called in C language, a structure called AR will be prepared on the Stack, regardless of the Implementation Details of the specific compiler. The basic structure of this AR is as follows.

The C compiler generates assembly code to allocate the AR on the stack whenever it encounters a statement called by the explain function. For example, the following C code:

void a(int i){    if(i==0){        i = 1;    }    else    {        printf("i = %d \n", i);    }}int main(int argc, char** argv){    a(1);}

When the program runs and runs the printf () Statement, the AR layout on the stack is as follows:

2. Use setjmp and longjmp to manipulate the AR to perform any redirection.

Then, how can we manipulate AR? One possible method is to calculate it based on the address of the local variable, for example, for the above function, when executing function a, the current AR address is the 8-byte address offset of parameter I, that is (char *) & I)-8. However, different C compilers and different hardware platforms generate different AR structure la S. Even on some platforms, AR will not be stored in the Stack. Therefore, this method is not applicable to AR operations.

Therefore, the C language provides a unified method to manipulate AR Through library functions, that is, setjmp and longjmp functions.

int setjmp(jmp_buf jb);void longjmp(jmp_buf jb, int r);

Setjmp is used to save the current AR to the jb variable;
Longjmp is used to set the current AR to jb and jump to the first statement after setjmp () is called. The result is equivalent to returning to the setjmp () after the execution is complete, but secretly modified the setjmp return value.

When setjmp () is called for the first time, 0 is always returned, and the return value is always changed to r after the jump through longjmp (jb, r), and r cannot be 0. In this way, it is easy for the program to determine whether longjmp () causes the jump to be executed until the result is returned by setjmp.

Setjmp/longjmp mainly jumps out from nested function calls.

#include 
  
   #include 
   
    jmp_buf jb;void a();void b();void c();int main(){    if(setjmp(jb)==0){        a();    }    printf("after a(); \n");    return 0;}void a(){    b();    printf("a() is called\n");}void b(){    c();    printf("b() is called\n");}void c(){    printf("c() is called\n");    longjmp(jb, 1);}
   
  

In c (), you can directly jump to main (). In fact, longjmp does not limit the jump destination. You can jump to any position and restore the current stack environment (stack balance ).

3. Exception Handling in C Language

Exception Handling is a method of error handling. The more common method of error handling in C language is to detect the function return value.

# Include
  
   
Int f1 () {if (1/* correctly executed */) {return 1 ;}else {return-1 ;}} int f2 () {if (0/* correct execution */) {return 1;} else {return-1 ;}} int main () {if (f1 () <0) {printf ("error handling 1 \ n"); exit (1) ;}if (f2 () <0) {printf ("error handling 2 \ n "); exit (2);} return 0 ;}
  

The above code shows common C language error handling methods. In rigorous software development, it is necessary to detect possible errors in each callback function call and handle them accordingly. The consequence is lengthy and tedious code. To handle errors in a unified manner, modern languages such as C ++, C #, and Java introduce exception handling mechanisms. The C ++ code for the same function is roughly as follows:

# Include
  
   
Class Ex1 {}; class Ex2 {}; void f1 () {printf ("entering f1 () \ n"); if (0/* correctly executed */) {} else {throw Ex1 ();} printf ("Exit f1 () \ n");} void f2 () {printf ("Enter f2 () \ n "); if (1/* correct execution */) {} else {throw Ex2 ();} printf ("Exit f2 () \ n");} int main () {try {f1 (); f2 ();} catch (Ex1 & ex) {printf ("handle error 1 \ n"); exit (1 );} catch (Ex2 & ex) {printf ("handle error 2 \ n"); exit (2);} return 0 ;}
  

Program output:

Enter f1 () processing error 1

It can be seen that exception handling makes the Code look more neat, the logic code is combined, and the error handling code is combined. The statement after throw is no longer executed. The execution stream jumps directly to the catch Block corresponding to the nearest try.

It can be inferred that,

Throw is responsible for two tasks: (1) completing the jump; (2) Restoring the stack AR; and try is responsible for saving the current AR.

This is basically the same as setjmp/longjmp. Therefore, it can be roughly written in C.

# Include
  
   
# Include
   
    
# Include
    
     
Jmp_buf jb; void f1 () {printf ("Enter f1 () \ n"); if (0/* correctly executed */) {} else {longjmp (jb, 1);} printf ("Exit f1 () \ n");} void f2 () {printf ("Enter f2 () \ n "); if (1/* correct execution */) {} else {longjmp (jb, 2);} printf ("Exit f2 () \ n");} int main () {int r = setjmp (jb); if (r = 0) {f1 (); f2 ();} else if (r = 1) {printf ("processing error 1 \ n"); exit (1) ;}else if (r = 2) {printf ("processing error 2 \ n "); exit (2);} return 0 ;}
    
   
  

Of course, the complete exception handling process is far more complex than the code here. We need to consider exception nesting and so on. Here we just give the simplest idea.

4. Do not use setjmp and longjmp in C ++.

C ++ provides direct support for exception handling. Unless extremely special, do not re-implement your own exception mechanism. In particular, a simple call to setjmp/longjmp may cause problems. For example

# Include
  
   
# Include
   
    
# Include
    
     
Class MyClass {public: MyClass () {printf ("MyClass: MyClass () \ n ");}~ MyClass () {printf ("MyClass ::~ MyClass () \ n ") ;}}; jmp_buf jb; void f1 () {MyClass obj; printf (" Enter f1 () \ n "); if (0/* correct execution */) {} else {longjmp (jb, 1);} printf ("Exit f1 () \ n");} void f2 () {printf ("Enter f2 () \ n"); if (1/* correctly executed */) {} else {longjmp (jb, 2 );} printf ("Exit f2 () \ n");} int main () {int r = setjmp (jb); if (r = 0) {f1 (); f2 ();} else if (r = 1) {printf ("processing error 1 \ n"); exit (1);} else if (r = 2) {printf ("processing error 2 \ n"); exit (2);} return 0 ;}
    
   
  

G ++ compilation, program output:

MyClass: MyClass () enters f1 () to handle error 1

Vc ++ compilation and program output:

MyClass: MyClass () enters f1 () MyClass ::~ MyClass () processing error 1

The local objects before the longjmp () Jump may not parse the structure (g ++) or the structure (VC ++). The C ++ standard does not explicitly require this. This type of code dependent on a specific compiler version should be avoided.

However, the throw keyword of C ++ can strictly guarantee the paired calls of local object structures and destructor.

5. Process exceptions Dialectically

To implement exception handling, the C ++ compiler must do more work for this, and will inevitably store more information directly or indirectly in AR, the compilation code that generates such information will inevitably reduce the running efficiency.

On the other hand, there are already a large number of C ++ function libraries and class libraries without strict Exception Handling. Compatible C libraries have no exception concept, the historical burden makes it difficult for C ++ to completely handle exceptions. In this regard, Java and C # have both implemented standard Exception Handling specifications for important libraries, and fully adopt the exception mechanism.

Interestingly, C ++ 11 deletes the exception specification in the standard and adds the notest keyword to declare a function. It does not throw an exception. It can be seen that the exception is not so popular.

The C ++ compiler also provides an option to disable exceptions. The following describes how to disable exceptions in VC ++.

However, C ++'s STL is widely used for exceptions. In fact, it is impossible to disable exceptions when STL is used. If STL is not used, what are the advantages of C ++? C ++ is a developer in constant conflicts and conflicts.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.