代码之家  ›  专栏  ›  技术社区  ›  JustWe

对于setjmp,alloca()的函数是什么?

  •  2
  • JustWe  · 技术社区  · 6 年前

    这个问题来自 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:

    拆卸后 阿洛卡(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 回复  |  直到 6 年前
        1
  •  2
  •   Petr Skocik    6 年前

    下面是一篇关于使用setjmp/longjmp/alloca实现COROS的文章: https://fanf.livejournal.com/105413.html .

    其思想是,为了使B在长时间跳回到A时保持它的完整上下文(不仅寄存器(由setjmp保留),而且本地的、堆栈上的变量),B需要它自己的堆栈,或者至少它需要确保A所做的一切不会覆盖B的变量。

    alloca 是一种在不钻研装配的情况下实现这一目标的方法。 分配器 基本上会比A在堆栈上移动更多的B,所以除非A使用深度递归或使其使用超过其堆栈的2Kib(在本例中)的任何东西,否则A和B将保持它们在堆栈上的局部变量分开。

    (这项技术很自然地不是严格符合C的,如果你在多重跳之间来回跳,它会更少。 malloc 'd堆。)

        2
  •  0
  •   JustWe    6 年前

    关于第二个问题的解决:

    int r 在GCC中,into数据段将给出相同的结果,即发布或调试。

    static int r = 0;