作者:寡妇毒_393 | 来源:互联网 | 2023-02-01 19:42
我正在阅读CSAPP,关于setjmp
和的章节longjmp
,并遇到以下代码片段:
int rc;
switch(setjmp(buf));
if (rc == 0)
foo();
else if (rc == 1)
printf("sth.");
else if (rc == 2)
printf("sth. other");
...
switch语句让我很困惑,有人可以为我解释一下C中switch语句的用法吗?
PS:这实际上是CSAPP(第二版)的错误,作者通过switch-case
在第三版中使用正常语句来解决这个问题.谢谢大家.
1> Lundin..:
首先,请注意setjmp
并且longjmp
被认为是令人难以置信的糟糕做法,最糟糕的意大利面条编程.任何教你使用这些功能的学习来源都应该受到极大的怀疑.
至于奇怪的switch语句存在的原因,是因为setjmp
标准对函数提出了许多人为要求.C11 7.13.1.1
环境限制setjmp宏的调用只能出现在以下某个上下文中:
- 选择或迭代语句的整个控制表达式;
- 关系或等于运算符的一个操作数与另一个操作数的整数常量表达式,结果表达式是选择或迭代语句的整个控制表达式;
- 一元的操作数!运算符,结果表达式是选择或迭代语句的整个控制表达式; 或
- 表达式语句的整个表达式(可能转换为void).
请注意,上面的最后一点允许使用代码(void) setjmp(env);
,因此问题中的switch语句主要是混淆.
C标准基本原理7.13.1解释了为什么这个"函数"具有这样的人为要求,即因为它必须实现为宏:
7.13.1.1 setjmp宏
对setjmp的一个建议要求是它可以像任何其他函数一样使用,也就是说,它可以在任何表达式上下文中调用,并且表达式正确评估setjmp的返回是直接还是通过调用到longjmp.不幸的是,setjmp作为传统被调用函数的任何实现都无法充分了解调用环境以保存在表达式评估中使用的任何临时寄存器或动态堆栈位置.(setjmp宏似乎只有在它扩展为内联汇编代码或调用特殊内置函数时才有帮助.)临时调用可能在初始调用setjmp时是正确的,但不太可能在由对longjmp的相应调用.这些考虑因素决定了setjmp只能从相当简单的表达式中调用的约束,这些表达式不太可能需要临时存储.
说白了:如果你要调用一个函数而不是一个宏,那么CPU/OS可能会堆掉你真正想要setjmp保存的各种寄存器,最值得注意的是程序计数器.(在C语言支持内联函数之前很久就已经指定了setjmp.)