这个问题来自我提出的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
之后查看堆栈中发生的事情。
问题1:
使用routineB
后,alloca(2048)
堆栈的活力是什么?
我听说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。
答案 0 :(得分:2)
这是一篇关于使用setjmp / longjmp / alloca:https://fanf.livejournal.com/105413.html实现coros的文章。
这个想法是为了让B保持它的完整上下文(不仅仅是寄存器(由setjmp保留)而且还有本地的堆栈变量)当长时间跳回A时,B需要它自己的堆栈或者至少需要确保A确实无法覆盖B的变量。
alloca
是一种在不钻研装配的情况下实现这一目标的方法。
alloca
基本上会在堆栈上进一步移动B而不是A,因此除非A使用深度递归或任何使其使用超过2KiB(在这种情况下)其堆栈的东西,否则A和B将保持他们的堆栈局部变量分开。
(这种技术很自然地不严格符合C,如果你在多个malloc
堆栈之间使用来回跳跃,那么它就更少了。)
答案 1 :(得分:0)
关于第二个问题的解决方案:
将int r
放入数据段将在GCC中发布或调试相同的结果。
static int r = 0;