C language a more elegant abnormal processing mechanism

xiaoxiao2021-04-08  6

Episode 16 A more elegant abnormal processing mechanism in C language

Author: Wang Shengxiang Source: Greek Competition Network

Http://www.csai.cn May 19, 2005

The last article made a deep explanation of the GOTO statement in the C language, in fact, the GOTO statement is the most original support form of the procedure and the structured programming. Later, in order to better, the exception handling programming mechanism is more convenient, making the programmer in the program developed by C language, can write more efficient and more friendly code modules with an exception handling mechanism. Thus, a more elegant exception handling mechanism in the C language is the setJMP () function and the longjmp () function. In fact, this anomalous process is not part of the C language, but two very tapered library functions implemented in the C standard library, maybe most C programmers friends are familiar with it, and By using the setjmp () function with the longjmp () function combination, the exception handling mechanism of the program is provided to the library system developed by many C language, such as the JPG resolution library, encryption, and the like. Perhaps this anomalous handling mechanism in the C language, compared to the GOTO statement, it is true, conceptually, an exception handling mechanism. The style of the style has always been more rigorous, and the protagonist who likes the root of the planing will not discard the comprehensive and in-depth study of this abnormal handling mechanism. Let's take a look. What is the role of SetJMP function? Just said before, SetJMP is a function provided in the C Standard Library, which is to save some status of the program currently run. Its function prototype is as follows: int setjmp (JMP_BUF ENV); this is the comment on it in MSDN, as follows: setjmp function Save the stack environment of the program, followed elsewhere, you can call the longjmp function Restore previously saved programs stack environments. When setJMP and longjmp combinations, they provide a mechanism for implementing "Non-local Goto") in the program. And this mechanism is often used to implement, transmit the program's control flow to the error handling module; or the normal return (RETURN) statement, or function of the function, etc., Restore to a previous call routine (i.e., functions). When the call to the setjmp function, the program currently stack environment is saved in the ENV parameter; when you call Longjmp, the previous environment will be restored according to this once saved variable, and the current program control flow will return to The program execution point when you call SetJMP. At this time, in the routine of the next control stream, all variables (except for the variable of the register type) can be accessed, and the variables of the LONGJMP function are included. SetJMP and longjmp do not have a well-supported semantics in C . Therefore, in the C program, use the exception handling mechanism provided by C . Ok, now I have a very sensible understanding of SetJMP, and I will not do too much comments, and then look at the longjmp function. What is the role of the longjmp function? Similarly, longjmp is also a function provided in the C Standard library. Its role is to recover the stack environment executed by the program, its function prototype as follows: void longjmp (JMP_BUF ENV, INT VALUE); this is a comment on it in MSDN The following: longjmp function is used to restore the stack environment saved when the SetJMP function called in the previous program.

When setJMP and longjmp combinations, they provide a mechanism for implementing "Non-local Goto") in the program. And this mechanism is often used to implement, transmitting the control flow of the program to the error handling module, or does not use the normal return statement, or the function of the function, so that the program can be restored to the previous one. Call routines (i.e., functions). When the call to the setJMP function, the current stack environment is saved in the ENV parameter; when the longjmp is called, the previous environment will be restored according to the variable that has been saved, and therefore the current program control flow, will return to the previous Call the execution point when setJMP. At this point, the value parameter value is returned by the SetJMP function, and the program continues to be executed. Also, in the routine of the next control flow, all variables it can access (except for variables of the register type), the variables included when the LONGJMP function is called, and the variable of the register type will not It is expected. The value returned by the SetJMP function must be a non-zero value. If the value parameter value transmitted by lonjmp is 0, the value returned by SetJMP is 1. Call LongJMP before calling the set of setjmp, otherwise the result is unpredictable. When using longjmp, follow the rules or restrictions: • Do not illustrate the variable of the register type will always remain unchanged. After calling longjmp, the variable of the register type in the routine will not be recovered by the control flow returned by SetJMP. • Do not use the longjmp function to achieve the control stream, from an interrupt processing routine, unless the captured exception is a floating point exception. In the latter case, if the program initially initials the floating point number package by calling the _fpreset function, it can be returned from the interrupt processing routine. · In the C program, be careful of the use of SetJMP and longjmp, should not support the Semantic Semantic Semantic in C for SetJMP and Longjmp. Therefore, in the C program, the exception handling mechanism provided by C will be safer.

Combine setjmp and longjmp, which is so powerful! It has now been a very sensible understanding of SetJMP and Longjmp, next to see an example, and to analyze from this example, the sample code is as follows (from MSDN): / * fpReset.c: this Program Uses Signal To set up A * routine for handling floating-point errors. * / #include #include #include #include #include #include < Math.h> #include 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, "Could not 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 OCC URS, JMPRET WILL BE SET to -1 and false * conditional will be executed. * / // Note ) {PrintF ("" "" Enter Two Numbers: "); Scanf ("% LF% LF ", & N1, & N2); // Note, the following statement may exceed usual, / / If the second variable input from the terminal is 0 value, R = N1 / N2; / * this won't be reached if error c c @ / printf ("/N/n%4.3G /% 4.3G =% 4.3g / n ", n1, n2, r); r = n1 * n2; / * this won't be reached if error ocurs. * / Printf ("

/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. * / / Note, the following statement is to restore the program status of the previous setJMP (Mark, -1);} void fpcheck (void) {cha r 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);} The running results of the program are as follows: Test for Invalid Operation - ENTER TWO NUMBERS: 1 2 1/2 = 0.5 1 * 2 = 2 The above program running results are normal.

There is also a situation in the operation of the program, as follows: Test for Invalid Operation - Enter Two Numbers: 1 0 Error 131: Divide by Zero huh! An exception occurred during the program operation (divided by 0), and this exception was captured by the exception processing module predefined by the program. Bar! Don't underestimate, this can be written in C language. Analyze SetJMP and Longjmp now to analyze the execution of the above program. Of course, this is mainly analyzed in the abnormality, the control transfer process of the program runs. Due to the limited number of articles, we simplify the unrelated code, so it is more likely to understand the execution of the control flow. As shown below. Ha ha! Whether the execution process of the program is now at a glance, the most critical is the call processing of setjjmp and longjmp functions. We analyze them separately. When the program is running to step 2, call the setjmp function that saves some status information of the program currently run, mainly the value of some system registers, such as SS, CS, EIP, EFLAGS, etc. Registers, which is especially important that EIP's value is equivalent to saving an execution point of a program run. This information is saved to the Mark variable, which is a variable that defined in a C standard library. After calling the SetJMP function to save the program status, the function returns 0 value, so the program is executed in step 3 and 4 steps. When executed in the fourth step, if the variable N2 is 0 value, then a floating point number is calculated, resulting in the control stream into the fphandler function, i.e., enters the first step. Then run to step 6, call the LONGJMP function, which will revert to the previous system register from the program status saved from the previous setjmp, ie the Mark variable. So I entered the step 7, pay attention, it is very important, in fact, after the call of the longjmp function, the program control stream (especially the value of EIP) is once again dramatically entered the internal part of the setjmp function, but this time The value returned by SetJMP is when the longjmp function is called, the second parameter passed is, i.e.,, so the program is connected to the execution of step 8. Summary is different from the GOTO statement. In the C language, setJMP () combined with longjmp (), providing programmers with a more elegant exception handling mechanism. It has the following features: (1) GOTO can only achieve local jump, while setjmp () combined with longjmp (), can effectively implement non-local (remote) jump of program control flow; (2) and goto statement Different, setJMP () combined with longjmp () provides a true exception handling mechanism.

转载请注明原文地址: http://www.9cbs.com/read-132827.html

New Post(0)