C. Several exception mechanisms
Introduction
This is a discussion about how to use the exception Mechanism in C. Let's talk about the setjmp internal mechanism of the magic function in C.
Use it to implement advanced exceptions. try... catch. Allow me to start a interview question first. It makes sense for computer interview questions, algorithm questions, and so on.
It will be easy to use when you encapsulate the basic library, because everyone will get you to pass. If you want to pass + 1...
Let's get started. The question is like this.
/** For interview questions, suppose an array of int a [] = {1, 2, 3, 4, 5, 6, 7}, n = 7 indicates the length, k = 2 indicates that the moving step * changes to 1234567 => 6712345. * Similarly, if k = 3 move three steps 1234567 => 5671234 *, implement a mobile function * void convert (int a [], int n, int k );*/
Basically speaking about algorithms. Here we mainly want to guide the exception mechanism through this problem.
// Array mobile function void convert (int a [], int n, int k) {int t = 1, I, j; // t is the condition for data record termination. // the first two are not necessary for moving. The latter is the case that the entire division has formed a cycle and does not need to be moved if ((! A) | (n <= 1) |! (K % = n) return; // calculate the optimal k and n k = k <0? K + n: k; // It starts to actually move. First, determine the number of shards. Generally, this is enough. In particular, it is necessary to perform the for (I = 0; t <n & I <k; ++ I) {// starts the loop, and ends the conditional loop to the for (j = (I + k) % n; j! = I; j = (j + k) % n) {++ t; int tmp = a [I]; a [I] = a [j]; a [j] = tmp ;}}}
About the above
// There is no need to move the first two items, and there is no need to move if ((! A) | (n <= 1) |! (K % = n) return;
It is the simplest exception Mechanism in C that has heard the if condition in advance to respond to exceptions. It should be the simplest and common way to handle exceptions.
Complete Test demo. c In the appendix
# Include <stdio. h> # include <stdlib. h> // array print function void aprint (int a [], int n); // array movement function void convert (int a [], int n, int k ); // Add an array to print the Macro. a can only be an array # define ALEN (a) \ sizeof (a)/sizeof (* a) # define APRINT (a) \ aprint (, ALEN (a)/** for interview questions, suppose there are arrays int a [] = {1, 2, 4, 5, 6, 7}, n = 7 representing the length, k = 2 indicates that the moving step * changes to 1234567 => 6712345. * Similarly, if k = 3 move three steps 1234567 => 5671234 *, implement a mobile function * void convert (int a [], int n, int k); */int main (Int argc, char * argv []) {// implement the subject logic int a [] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; APRINT (a); convert (a, ALEN (a), 4); APRINT (a); convert (a, ALEN (a),-4 ); APRINT (a); return system ("pause");} // array print function void aprint (int a [], int n) {int I =-1; printf ("now data:"); while (++ I <n) printf ("% d", a [I]); putchar ('\ n ');} // array mobile function void convert (int a [], int n, int k) {int t = 1, I, j; // t is the condition for data record termination. // the first two are unnecessary for moving, There is a division and formation cycle, and you do not need to move if ((! A) | (n <= 1) |! (K % = n) return; // calculate the optimal k and n k = k <0? K + n: k; // It starts to actually move. First, determine the number of shards. Generally, this is enough. In particular, it is necessary to perform the for (I = 0; t <n & I <k; ++ I) {// starts the loop, and ends the conditional loop to the for (j = (I + k) % n; j! = I; j = (j + k) % n) {++ t; int tmp = a [I]; a [I] = a [j]; a [j] = tmp ;}}}View Code
Do you think it is very simple? This is the essence of exceptions,Branch.
Preface
Here, we will talk about another processing method similar to if.
The addition of default is also a means of exception handling.
In C development or a program interface design, a very old design has an exception judgment interface method which is processed by the return method.
Suppose we need to write a function to return two functions with division of numbers.
# Define _ RT_ OK (0) // returned macro with correct results # define _ RT_EB (-1) // error base type, which is available for all errors, # define _ RT_EP (-2) // Parameter Error # define _ RT_EM (-3) // Memory Allocation Error # define _ RT_EC (-4) // if the file has been read or the link is closed # define _ RT_EF (-5) // if the file fails to be opened, int div (double a, double B, double * pc) {if (B = 0 |! Pa) return _ RT_EP; * pc = a/B; return _ RT_ OK ;}
The above idea is a retro routine. It may only be visible in the C interface encapsulation. It is especially honest. This technique is worth it.
Returns the status code of the function running, returns the final result value through the pointer, and pulls a bit more. The above interface design has a flaw, when calling
A large amount of if judgment is required. For example, backend development. For illegal requests, direct fake. (exit) does not need to return a status code to the front end. This reduces bandwidth.
Now, basically, the exception handling methods in simple development are described briefly. try... catch mechanism will be implemented later.
Body
Here we will first look at the Magic function for exception handling in C. A function that jumps more than goto. It supports jumping between functions. First, we will look at an implemented function declaration.
// Function prototypesint __cdecl setjmp( _Out_ jmp_buf _Buf );
__declspec(noreturn) void __cdecl longjmp( _In_ jmp_buf _Buf, _In_ int _Value );
If you do not understand the above keywords (on VS), ignore them directly. The first function setjmp sets the flag. The first time you use it, return 0. The value returned here is the value set by the second parameter of longjmp.
There is an undefined phenomenon here. Do not use longjmp to return 0 test code.
# Include <stdio. h> # include <stdlib. h> # include <setjmp. h> // test the basic code longjmp (jbf, 0) int main (void) {volatile a = 0; jmp_buf jbf; int rt; rt = setjmp (jbf ); if (rt = 0) {printf ("a % d => % d \ n", ++ a, rt); if (a = 2) exit (0);} else {printf ("B % d => % d \ n", ++ a, rt );} // skip if (a = 1) longjmp (jbf, 0); return system ("pause ");}
The running result is undefined based on the platform.
.
There is also a jmp_buf Structure
#define _JBLEN 16 #define _JBTYPE int typedef struct __JUMP_BUFFER { unsigned long Ebp; unsigned long Ebx; unsigned long Edi; unsigned long Esi; unsigned long Esp; unsigned long Eip; unsigned long Registration; unsigned long TryLevel; unsigned long Cookie; unsigned long UnwindFunc; unsigned long UnwindData[6]; } _JUMP_BUFFER;
It is mainly to save the current register information so that it can jump to longjmp. This requires compilation knowledge. I will not. I will have the opportunity to learn it again.
I hope that the basic setjmp longjmp api of C can be clarified here. The following describes a complete case for exception handling.
# Include <stdio. h> # include <stdlib. h> # include <setjmp. h> // trigger operation with an exception mechanism double jmpdiv (jmp_buf jbf, double a, double B); // set the exception mechanism int main (int argc, char * argv []) {jmp_buf jbf; double a = 2.0, B = 0, c; int I = 0; // random number while (++ I <= 10) {printf ("% d =>", I); // The value returned by the first call of setjmp is 0 switch (setjmp (jbf) {case 0: B = rand () % 5; c = jmpdiv (jbf, a, B); // try part printf ("% lf/% lf = % lf \ n", a, B, c ); break; Case-1: // catch part fprintf (stderr, "throw new div is zero! \ N "); break; default: fprintf (stderr," uncat error! ") ;}} Return 0;} double jmpdiv (jmp_buf jbf, double a, double B) {// throw an exception if (B = 0) longjmp (jbf, -1); return a/B ;}
Sorry, it's a bit of water today. poor description. after all, there are two APIs. the usage is also fixed. C is mainly used in coroutine design. if else switch goto can solve the exception.
The following describes how to encapsulate try... catch into a macro.
# Include <setjmp. h>/* try start operation */# define TRYBEGIN (var) {\ jmp_buf var; \ switch (setjmp (var) {\ case 0: /* catch detection error value */# define CATCH (z) \ break; \ case z:/* default captured error information. it is recommended that at the end of CATCH, if CATCH exists */# define CATCHBASE () \ default:/* try end mark */# define TRYEND \ break; \}/* throw an exception */# define THROW (var, z) \ longjmp (var, z)
Simple and practical:
TRYBEGIN (jbf) {puts ("first run to this");} CATCH (1) {} CATCHBASE () {} TRYEND
Here, we will share a simple example of using setjmp and longjmp to implement coroutine.
# Include <stdio. h> # include <setjmp. h> // variable jmp_buf _ mtask, _ ctask used for inter-function stack jump; // declare the test interface void cushion (void); void child (void); int I = 0; // test the main logic. int main (void) {if (! Setjmp (_ mtask) cushion (); for (I = 0; I <5; ++ I) {puts ("Parent"); if (! Setjmp (_ mtask) longjmp (_ ctask, 1) ;}// declare the test interface void cushion (void) {char space [1024]; space [1023] = 1; child () ;}void child (void) {for (I = 0; I <5; ++ I) {puts ("Child loop begin "); // return 0 if (! Setjmp (_ ctask) longjmp (_ mtask, 1); puts ("Child loop end"); if (! Setjmp (_ ctask) longjmp (_ mtask, 1 );}}
I want it to run a few times and it will end directly. It will not be running. There are still a lot of setjmp pitfalls. the stack is not enough, and the variable status is recommended.
I will try it several times. I don't need to go into it. I just need to know that setjmp + longjmp can be used to implement the exception mechanism try catch. It's hard to implement finally.
A little bit. You can combine the above coroutine. You can also think about it.
At this point, the essence of the exception mechanism is basically over.Branch + jump
Postscript
Errors are inevitable. Communication and modification. mutual awareness. For more information, see setjmp. h.
Correct use of http://blog.codingnow.com/2010/05/setjmp.html for setjmp
I will share some practical case studies later. How to Design and optimize performance ~~~