allocamp的alloca()的功能是什么?

时间:2018-05-23 08:11:32

标签: c coroutine longjmp setjmp alloca

这个问题来自我提出的Practical usage of setjmp and longjmp in CHow 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。

2 个答案:

答案 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;