C语言中setjmp与longjmp的行为理解及代码执行流程疑问
setjmp/longjmp程序执行逻辑解释
核心前提
C标准明确规定:如果调用longjmp时,此前调用setjmp保存上下文的函数已经执行完毕返回,那么该操作的行为是未定义行为,程序的表现完全取决于编译环境、运行平台,没有统一的标准结果,你看到的输出只是当前环境下的特定表现。
你当前环境下的执行流程拆解
我们按照你给出的输出反推实际执行过程:
- main函数先执行第17行代码,输出
hello main - 执行第18行调用
hello()函数,进入函数后执行第8行的setjmp(env):- 首次调用
setjmp会将当前的栈指针(sp)、帧指针(fp)、程序计数器(pc)等值保存到env全局变量中,同时返回0 - 因为
ret=0,不进入if分支,直接执行第13行输出hello called hello函数执行完毕,返回main函数
- 首次调用
- 回到main函数执行第19行,输出
after hello call,接着执行第20行的longjmp(env, 1) longjmp恢复env中保存的寄存器上下文:- 程序跳回
hello函数中第8行setjmp的返回位置,这次setjmp返回值为传入的1,即ret=1 - 进入if分支,执行第11行输出
error - 继续执行第13行输出
hello called
- 程序跳回
- 此时
hello函数要执行返回逻辑,但因为hello此前已经返回过一次,栈结构已经被破坏,你预期的“返回main第19行”的情况没有发生,在你当前的运行环境中,栈上保存的返回地址已经被篡改,程序直接退出,因此没有出现无限循环。
认知误区说明
你以为longjmp跳转后hello执行完会正常回到main第19行的前提是:setjmp所在的hello函数栈帧是完整合法的。只有在hello函数未返回时,在它的下级调用函数中执行longjmp跳转,才能保证栈帧合法,返回逻辑符合预期。你代码中的使用方式本身就不符合标准要求,因此不会按照你的预期执行。
内容的提问来源于stack exchange,提问作者InsaneCoder
相关产品推荐
相关产品推荐

