Базовый CS с нуля
Функции и стек вызовов: обзор с выбором ответа
Шесть вопросов, охватывающих весь юнит. Каждый просит рассуждать о том, что реально делает машина при вызове функции, — не воспроизвести определение, а предсказать состояние стека, путь управления и где живут данные.
Убедитесь, что вы связываете механизм вызова, кадр стека, передачу параметров, область видимости и время жизни, а также переполнение стека в одну целостную модель того, как работает вызов функции на уровне машины.
Тело функции живёт по одному адресу. Одна и та же функция вызывается из трёх разных мест программы. Как каждый вызов возвращается к нужной вызывающей стороне?
main вызывает outer, outer вызывает inner. Пока выполняется inner, что лежит на стеке и в каком порядке?
Функция add(x, y) вызывается как add(3, 5). Где живут значения 3 и 5, пока выполняется add, и что это гарантирует?
Функция f объявляет локальную переменную result. После возврата f код в main пытается использовать result. Что верно?
countdown(n) возвращается, когда n < 0, иначе вызывает countdown(n - 1). Каково максимальное число кадров на стеке одновременно для countdown(3)?
Рекурсивная функция выпущена без достижимого базового случая. Что происходит во время выполнения и почему так быстро?
Сквозная линия юнита — это один механизм, увиденный с разных сторон: CALL сохраняет адрес возврата и переходит к фиксированному телу; каждый вызов кладёт LIFO-кадр стека, хранящий этот адрес возврата плюс локальные переменные функции; параметры копируются внутрь при CALL, а результат отдаётся обратно при RET; область видимости и время жизни локальной переменной ограничены её кадром, поэтому при возврате она исчезает; а рекурсия — это та же укладка кадра, повторённая снова, безопасная только при достижимом базовом случае — без него кадры громоздятся, пока стек не переполнится.