【发布时间】:2018-11-02 03:13:21
【问题描述】:
这个问题来自我问的Practical usage of setjmp and longjmp in C和How to implement coroutine within for loop in c。
jmp_buf bufferA, bufferB;
void routineB(); // forward declaration
void routineA()
{
int r = 0;
printf("(A1)\n");
if (setjmp(bufferA) == 0) {
r++;
alloca(2048);
routineB();
}
printf("(A2) r=%d\n",r);
if (setjmp(bufferA) == 0) {
r++;
longjmp(bufferB, 1);
}
printf("(A3) r=%d\n",r);
if (setjmp(bufferA) == 0) {
r++;
longjmp(bufferB, 1);
}
printf("(A4) r=%d\n",r);
}
void routineB()
{
int r = 0;
printf("(B1)\n");
if (setjmp(bufferB) == 0) {
r++;
longjmp(bufferA, 1);
}
printf("(B2) r=%d\n", r);
if (setjmp(bufferB) == 0) {
r++;
longjmp(bufferA, 1);
}
printf("(B3) r=%d\n", r);
if (setjmp(bufferB) == 0) {
r++;
longjmp(bufferA, 1);
}
printf("(B4) r=%d never reach\n", r);
}
int main()
{
printf("main\n");
routineA();
return 0;
}
我正在研究 C. 的协程实现,并试图查看longjmp 之后堆栈中发生了什么。
问题一:
在使用alloca(2048) 之后,使routineB 的堆栈存活的魔法是什么?
我听说alloca 是邪恶的,但为什么它使堆栈看起来像扩展了。
我应该这样使用它吗?
输出:
main
(A1)
(B1)
(A2) r=1
(B2) r=1
(A3) r=2
(B3) r=2
(A4) r=3
问题 2:
删除alloca(2048) 后。告诉编译器禁用优化(-O2)后给出不同的结果。
-O0
main
(A1)
(B1)
(A2) r=1
(B2) r=6356584
(A3) r=2
(B3) r=6356584
(A4) r=3
-O2
main
(A1)
(B1)
(A2) r=1
(B2) r=0
(A3) r=1
(B3) r=0
(A4) r=1
如果它不是未定义的,如何使代码获得相同的行为?如果是,请忘记 Q2。
【问题讨论】:
-
就像我解释的here,代码调用了未定义的行为。您不应该在函数之间进行这种跳转。
-
@AjayBrahmakshatriya 所以我将简单地将
longjmp视为一个特殊的return。 -
@Jiu,
longjmp并不总是回报。仅当相应的setjmp位于嵌套调用集中较早的函数中时,它才会终止该函数。如果setjmp在同一个函数中,它就像一个普通的goto。setjmp也可能是嵌套的许多步骤。所以它根本不像return。 -
@AjayBrahmakshatriya 谢谢!使用
longjmp&setjmp的最佳总结。