6. non-local jumps
(1) setjmp and LONGJMP statements
Header file |
#include <setjmp.h> |
Function |
int* setjmp (Jum_buf env); |
return value |
The direct call returns 0 and returns a non-0 value if returned from the LONGJMP call |
Function |
Set jump points for non-local jumps |
|
Function |
void longjmp (jmp_buf env, int val); |
Function |
Perform a non-local turn, Val is the return value |
Parameters |
ENV: A special type of jmp_buf. This data type is a form of an array that holds information that can be used to restore the stack state when calling longjmp (for example, the value of each register, but not the data such as the thread stack local variables). In general, the ENV variable is a global variable because it needs to be referenced from another function. |
Note |
(1) C program lacks exception handling method, can use non-local jump to handle the exception of C program. (2) TheGoto statement is limited to intra-function jumps , and longjmp is not limited to. |
"Programming Experiment" non-local jump
Process_jmp.c
#include <setjmp.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>#include<string.h>#defineTok_add 5#defineTok_sub 6Char*Constprompt ="Cal:";//command line promptJmp_buf env; //Save run environment, non-local jump for functions between the jump//command-line format such as: Add 3 5 or Sub 5 3voidDo_line (Char* line);//parsing and executing command-line contentvoidCmd_add (void);voidCmd_sub (void);intGet_token (Char* line);//To get an identifier from a command-line argumentintMainintargcChar*argv[]) {ssize_t size= strlen (Prompt) *sizeof(Char); Charbuff[ the]; ssize_t Len=0; //set Jump points if(SETJMP (ENV) <0){//direct call returns 0, when jumping from longjmp, returns the Val value specified in longjmp//Here we set Val to positive, less than 0 means the setjmp call failed! Perror ("setjmp Error"); Exit (1); } //Output PromptWrite (Stdout_fileno, prompt, size); while(1) {len= Read (Stdin_fileno, Buff, the); if(Len <0) Break; Buff[len-1] =0; Do_line (Buff); Write (Stdout_fileno, prompt, size); } return 0;}voidDo_line (Char*Line ) { intcmd =Get_token (line); Switch(cmd) { CaseTok_add:cmd_add (); Break; Casetok_sub:cmd_sub (); Break; default: fprintf (stderr,"Error command\n"); }}voidCmd_add (void){ inti =Get_token (NULL); intj =Get_token (NULL); printf ("Result:%d +%d =%d\n", I, J, i +j);}voidCmd_sub (void){ inti =Get_token (NULL); intj =Get_token (NULL); printf ("Result:%d-%d =%d\n", I, J, I-j);}Static intIs_number (Char*Item) { intRET =1; intLen =strlen (item); inti =0; for(i=0; i<len; i++) {ret= Ret && ('0'<= Item[i]) && (Item[i] <='9'); if(ret = =0) Break; } returnret;}intGet_token (Char*Line ) { //format Add 3 4//Sub 7 5 Char* Item = strtok (line," "); if(Line! =NULL) { if(!STRCMP ("Add", item))returnTok_add; if(!STRCMP ("Sub", item))returntok_sub; }Else{ if(Is_number (item)) {inti =atoi (item); returni; }Else{fprintf (stderr,"Arg not number\n"); LONGJMP (env,1);//1 indicates the return value of setjmp after jumping to a jump point (setjmp) } }}
(2) The influence of longjmp on various variables
Variable type |
Affected situation |
Global variables, static variables, and volatile variables |
Cannot revert to original value |
Register variable |
Can revert to original value |
Automatic variables |
Optimization may be restored after compilation |
① the variable stored in the memory will have a value of longjmp , The variables in the CPU and floating-point registers revert to the value when the setjmp is called. .
When ② is not optimized , automatic variables, register variables, global variables, static variables, and volatile variables are stored in memory (i.e., the Register storage class description of the Reg_var variable is ignored).
③ and optimized ,Auto_var and Reg_var are stored in registers (even if Auto_var is not declared as register), andvolatile variables are still stored in memory .
④ Global, static, and volatile variables are not affected by optimizations, and when LONGJMP is called, their values are the most recently rendered values.
⑤ If you are writing a portable program that uses a non-local jump , you must use the volatile attribute .
The effect of "programming experiment" longjmp on variables
Longjmp_var.c
#include <setjmp.h>#include<stdio.h>#include<stdlib.h>#include<malloc.h>intglobal_var;jmp_buf env;intShowintG_v,intS_v,intA_v,intR_v,intM_v,intv_v);intF1 (intG_v,intS_v,intA_v,intR_v,intM_v,intv_v);voidF2 ();intMainintargcChar*argv[]) { Static intSta_var; intAuto_var; Register Reg_var; int* Heap_var = (int*)malloc(sizeof(int)); volatile intVola_var;//Volatile variableGlobal_var=1; Sta_var =2; Auto_var =3; Reg_var=4; *heap_var =5; Vola_var =6; intK =0; if(k = setjmp (env)) <0) {perror ("setjmp Error"); }Else if(k = =1) {printf ("After longjmp:\n"); Show (Global_var, Sta_var, Auto_var, Reg_var,*Heap_var, Vola_var); Exit (0); } Global_var=Ten; Sta_var = -; Auto_var = -; Reg_var= +; *heap_var = -; Vola_var = -; printf ("before longjmp:\n"); F1 (Global_var, Sta_var, Auto_var, Reg_var,*Heap_var, Vola_var); return 0;}intShowintG_v,intS_v,intA_v,intR_v,intM_v,intV_v) {printf ("Global:%d, static:%d, Auto:%d, Reg:%d, heap:%d Vola:%d\n", G_v, S_v, A_v, R_v, M_v, V_v);}intF1 (intG_v,intS_v,intA_v,intR_v,intM_v,intV_v) {Show (G_v, S_v, A_v, R_v, M_v, V_v); F2 ();}voidF2 () {longjmp (env),1);}/*output Result: [[email protected] 5.process]# gcc-o bin/longjmp_var src/longjmp_var.c [[email protected] 5.process]# Bin/long Jmp_var before Longjmp:global:10, static:20, auto:30, reg:40, heap:50 vola:60 after long Jmp:global:10, Static:20, auto:30, reg:40, heap:50 vola:60 [[email protected] 5.process]# Gcc-o-o bin/longjmp_v AR src/longjmp_var.c [[email protected] 5.process]# Bin/longjmp_var before Longjmp:global: Ten, static:20, auto:30, reg:40, heap:50 vola:60 after Longjmp:global:10, static:20, Auto:3, Reg:4 , heap:50 vola:60*/
5th Chapter Process Environment (5) _ Non-local jump