Ответы:
Кадр стека - это кадр данных, который помещается в стек. В случае стека вызовов кадр стека будет представлять вызов функции и данные ее аргумента.
Если я правильно помню, адрес возврата функции помещается сначала в стек, затем в аргументы и место для локальных переменных. Вместе они составляют «кадр», хотя это, скорее всего, зависит от архитектуры. Процессор знает, сколько байтов находится в каждом кадре, и соответственно перемещает указатель стека, когда кадры выталкиваются и выталкиваются из стека.
Существует большая разница между стеками вызовов более высокого уровня и стеком вызовов процессора.
Когда мы говорим о стеке вызовов процессора, мы говорим о работе с адресами и значениями на уровне байтов / слов в сборке или машинном коде. Существуют «стеки вызовов», когда речь идет о языках более высокого уровня, но это инструмент отладки / выполнения, управляемый средой выполнения, так что вы можете регистрировать, что пошло не так с вашей программой (на высоком уровне). На этом уровне такие вещи, как номера строк, имена методов и классов, часто известны. К тому времени, когда процессор получает код, он совершенно не имеет понятия об этих вещах.
Если вы хорошо понимаете стек, то вы поймете, как работает память в программе, и если вы поймете, как память работает в программе, вы поймете, как хранится функция в программе, и если вы поймете, как хранится функция в программе, вы поймете, как работает рекурсивная функция, и если вы поймете, как работает рекурсивная функция, вы поймете, как работает компилятор, и если вы поймете, как работает компилятор, ваш ум будет работать как компилятор, и вы очень легко отладите любую программу
Позвольте мне объяснить, как работает стек:
Сначала вы должны знать, как функции представлены в стеке:
Куча хранит динамически распределяемые значения.
Стек хранит значения автоматического распределения и удаления.
Давайте разберемся с примером:
def hello(x):
if x==1:
return "op"
else:
u=1
e=12
s=hello(x-1)
e+=1
print(s)
print(x)
u+=1
return e
hello(4)
Теперь разберитесь в частях этой программы:
Теперь давайте посмотрим, что такое стек и что такое части стека:
Выделение стека:
Помните одну вещь: если условие возврата какой-либо функции удовлетворяется, независимо от того, загружены ли локальные переменные или нет, она немедленно вернется из стека со своим фреймом стека. Это означает, что всякий раз, когда любая рекурсивная функция получает базовое условие, и мы помещаем возврат после базового условия, базовое условие не будет ждать загрузки локальных переменных, которые находятся в части «else» программы. Он немедленно вернет текущий кадр из стека, после чего следующий кадр теперь находится в записи активации.
Смотрите это на практике:
Распределение блока:
Поэтому теперь, когда функция встречает оператор return, она удаляет текущий кадр из стека.
При возврате из стека значения будут возвращаться в обратном порядке, в котором они были размещены в стеке.
hello()
он рекурсивно вызвал, hello()
который затем (снова) рекурсивно вызвал hello()
, а глобальный фрейм - это оригинальная функция, которая вызвала первый hello()
?
Быстрое завершение. Может быть, у кого-то есть лучшее объяснение.
Стек вызовов состоит из 1 или нескольких стековых кадров. Каждый кадр стека соответствует вызову функции или процедуры, которая еще не завершена с возвратом.
Чтобы использовать кадр стека, поток сохраняет два указателя, один из которых называется указателем стека (SP), а другой - указателем кадра (FP). SP всегда указывает на «вершину» стека, а FP всегда указывает на «вершину» кадра. Кроме того, поток также поддерживает программный счетчик (ПК), который указывает на следующую команду, которая будет выполнена.
В стеке хранятся следующие данные: локальные переменные и временные значения, фактические параметры текущей инструкции (процедура, функция и т. Д.)
Существуют разные соглашения о вызовах, касающиеся очистки стека.
«Стек вызовов состоит из кадров стека ...» - Википедия
Фрейм стека - это то, что вы кладете в стек. Это структуры данных, которые содержат информацию о подпрограммах для вызова.
У программистов могут возникнуть вопросы о фреймах стека не в широком смысле (что это единичная сущность в стеке, которая обслуживает только один вызов функции и сохраняет адрес возврата, аргументы и локальные переменные), но в узком смысле - когда термин stack frames
упоминается в контекст параметров компилятора.
Независимо от того, имел в виду автор вопроса или нет, но концепция стекового фрейма с точки зрения параметров компилятора - очень важная проблема, которая здесь не рассматривается в других ответах.
Например, компилятор Microsoft Visual Studio 2015 C / C ++ имеет следующий параметр, связанный с stack frames
:
GCC имеют следующее:
Компилятор Intel C ++ имеет следующее:
который имеет следующий псевдоним:
Delphi имеет следующую опцию командной строки:
В этом конкретном смысле, с точки зрения компилятора, кадр стека - это просто код входа и выхода для подпрограммы , который вставляет привязку к стеку - который также может использоваться для отладки и обработки исключений. Инструменты отладки могут сканировать данные стека и использовать эти привязки для обратного отслеживания, находясь call sites
в стеке, то есть для отображения имен функций в том порядке, в котором они были вызваны иерархически. Для архитектуры Intel это push ebp; mov ebp, esp
либо enter
для входа, mov esp, ebp; pop ebp
либо leave
для выхода.
Вот почему для программиста очень важно понять, что такое стековый фрейм, когда дело доходит до опций компилятора - потому что компилятор может контролировать, генерировать этот код или нет.
В некоторых случаях кадр стека (код входа и выхода для процедуры) может быть пропущен компилятором, и переменные будут напрямую доступны через указатель стека (SP / ESP / RSP), а не через удобный базовый указатель (BP / ESP / РСП). Условия пропуска стекового фрейма, например:
Пропуск кадров стека (код входа и выхода для подпрограммы) может сделать код меньше и быстрее, но это также может отрицательно повлиять на способность отладчиков отслеживать данные в стеке и отображать их для программиста. Это параметры компилятора, которые определяют, при каких условиях функция должна иметь код входа и выхода, например: (a) всегда, (b) никогда, (c) при необходимости (с указанием условий).
Кадр стека - это упакованная информация, связанная с вызовом функции. Эта информация обычно включает аргументы, передаваемые в функцию, локальные переменные и куда возвращаться после завершения. Запись активации - это другое имя стекового фрейма. Компоновка кадра стека определяется в ABI производителем, и каждый компилятор, поддерживающий ISA, должен соответствовать этому стандарту, однако схема компоновки может зависеть от компилятора. Обычно размер кадра стека не ограничен, но существует концепция, называемая «красная / защищенная зона», позволяющая системным вызовам ... и т. Д. Выполняться без вмешательства в кадр стека.
Всегда есть SP, но на некоторых ABI (например, ARM и PowerPC) FP не обязателен. Аргументы, которые нужно было поместить в стек, можно сместить только с помощью SP. Будет ли сгенерирован кадр стека для вызова функции или нет, зависит от типа и количества аргументов, локальных переменных и от того, как вообще доступны локальные переменные. В большинстве ISA, во-первых, используются регистры, и если имеется больше аргументов, чем регистров, выделенных для передачи аргументов, они помещаются в стек (например, x86 ABI имеет 6 регистров для передачи целочисленных аргументов). Следовательно, иногда некоторые функции не нуждаются в размещении кадра стека в стеке, просто адрес возврата помещается в стек.