C语言中有一个很不常用的头文件:setjmp.h。
这个头文件是C语言底层实现的,不像math.h里面的函数都是纯C语言实现的。
setjmp.h包含两个函数:
- longjmp 跳转到某个位置
- setjmp 设置一个跳转位置
setjmp用于设置一个语句标号,longjmp用于跳到某个语句标号。
这两个函数一结合,功能比goto还要强大。
#include/* printf */#include /* jmp_buf, setjmp, longjmp */main(){ jmp_buf env; int val; val=setjmp(env); printf ("val is %d\n",val); if (!val) longjmp(env, 1); return 0;}
输出为
val is 0
val is 1setjmp函数的返回值有两种情况:
- 如果是创建“语句标号”,总是返回0,表示创建“语句标号”成功
- 如果是被longjmp跳转来的,那么返回值就表示“从何处跳转来的”,这个值也是一个int,是longjmp跳转来的时候指定的
longjmp的两个参数:
- env参数表示想要跳转到的“语句标号”
- number参数表示“我是谁”,也就是主跳函数的ID,这个ID最终会被setjmp返回,用来判断跳转来源。
下面再举一个例子:在学校每天都是吃饭、学习、睡觉,周而复始、永不停息。用C语言如何描述这个过程呢?
#include#include #include using namespace std;jmp_buf eat_jump, sleep_jump, study_jump;void eat() { int value = setjmp(eat_jump); if (value == 0)return; cout << "新的一天开始了,吃饭、学习、睡觉" << endl; system("@pause"); cout << "eat" << endl; longjmp(study_jump, 1);}void sleep() { int value = setjmp(sleep_jump); if (value == 0)return;//如果是第一次创建,那就不要执行了 cout << "sleep" << endl; longjmp(eat_jump, 1);}void study() { int value = setjmp(study_jump); if (value == 0)return; cout << "study" << endl; longjmp(sleep_jump, 1);}int main() { sleep(); study(); eat(); longjmp(eat_jump, 1);}
输出为:
新的一天开始了,吃饭、学习、睡觉请按任意键继续. . .eatstudysleep新的一天开始了,吃饭、学习、睡觉请按任意键继续. . .eatstudysleep新的一天开始了,吃饭、学习、睡觉请按任意键继续. . .eatstudysleep新的一天开始了,吃饭、学习、睡觉请按任意键继续. . .eatstudysleep新的一天开始了,吃饭、学习、睡觉请按任意键继续. . .eatstudysleep新的一天开始了,吃饭、学习、睡觉请按任意键继续. . .eatstudysleep新的一天开始了,吃饭、学习、睡觉请按任意键继续. . .
这样的生活太单调了,最起码应该是随机一些:我吃了饭,可能睡觉也可能学习;我睡了觉,可能吃饭也可能学习;我学了习,可能吃饭也可能睡觉。
#include#include #include using namespace std;jmp_buf eat_jump, sleep_jump, study_jump;const int EAT = 1, SLEEP = 2, STUDY = 3;void eat() { int value = setjmp(eat_jump); if (value == 0)return; cout << "新的一天开始了,吃饭、学习、睡觉" << endl; system("@pause"); cout << "eat after " << (value == SLEEP ? "sleep" : "study") << endl; if (rand() % 2 == 0) longjmp(study_jump, EAT); else longjmp(sleep_jump, EAT);}void sleep() { int value = setjmp(sleep_jump); if (value == 0)return;//如果是第一次创建,那就不要执行了 cout << "sleep after " << (value == EAT ? "eat" : "study") << endl; if (rand() % 2 == 0) longjmp(eat_jump, SLEEP); else longjmp(study_jump, SLEEP);}void study() { int value = setjmp(study_jump); if (value == 0)return; cout << "study after " << (value == EAT ? "eat" : "sleep") << endl; if (rand() % 2 == 0) longjmp(sleep_jump, STUDY); else longjmp(eat_jump, STUDY);}int main() { srand(0); sleep(); study(); eat(); longjmp(eat_jump, 1);}
goto虽好,可不要贪杯呀。