Какова функция alloca () с setjmp? - PullRequest
0 голосов
/ 23 мая 2018

Этот вопрос возник из Практического использования setjmp и longjmp в C и Как реализовать сопрограмму внутри цикла for в 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 голосов
/ 24 мая 2018

О решении Второго вопроса:

Помещение int r в сегмент данных даст тот же результат, либо освобождение, либо отладка в GCC.

static int r = 0;
0 голосов
/ 23 мая 2018

Вот статья о реализации coros с помощью setjmp / longjmp / alloca: https://fanf.livejournal.com/105413.html.

Идея состоит в том, что для того, чтобы B сохранил свой полный контекст (не только регистры (сохраняемые setjmp), но и локальные переменные в стеке), когда при длинном переходе назад к A, B нужен свой собственный стекили, по крайней мере, нужно убедиться, что все, что делает A, не перезапишет переменные B.

alloca - это способ достичь этого без погружения в сборку.alloca будет в основном перемещать B намного дальше в стеке, чем A, так что если A не использует глубокую рекурсию или что-либо, что заставит его использовать более 2 КБ (в нашем случае) своего стека, A и B будут сохранятьлокальные переменные стека разделены.

(Этот метод, естественно, не совсем соответствует C, и было бы еще меньше, если бы вы использовали переходы вперед-назад между несколькими malloc 'd стеками.)

...