Поясніть поняття рами стека в двох словах


200

Здається, я розумію стек виклику в дизайні мови програмування. Але я не можу знайти (мабуть, просто не шукаю досить важко) жодного гідного пояснення, що таке фрейм стека .

Тому я хотів би попросити когось пояснити це мені кількома словами.

Відповіді:


195

Кадр стека - це кадр даних, який висувається на стек. У випадку стека виклику кадр стека представлятиме функціональний виклик та його аргументаційні дані.

Якщо я добре пам'ятаю, повернення функції спочатку висувається на стек, а потім аргументи та простір для локальних змінних. Разом вони роблять "кадр", хоча це, ймовірно, залежить від архітектури. Процесор знає, скільки байтів знаходиться в кожному кадрі, і відповідно переміщує покажчик стека, коли кадри висуваються і вискакують зі стека.

Редагувати:

Існує велика різниця між стеками викликів вищого рівня та стеком викликів процесора.

Коли ми говоримо про стек викликів процесора, ми говоримо про роботу з адресами та значеннями на рівні байтів / слів у складанні або машинному коді. Існують "стеки викликів", коли мова йде про мови вищого рівня, але вони є інструментом налагодження / виконання, керованим середовищем виконання, щоб ви могли зафіксувати те, що пішло не так у вашій програмі (на високому рівні). На цьому рівні часто відомі такі речі, як номери рядків, назви методів та класів. На той момент, коли процесор отримує код, він абсолютно не має поняття про ці речі.


6
"Процесор знає, скільки байтів знаходиться в кожному кадрі і відповідно переміщує покажчик стека, коли кадри висуваються і вискакують зі стека." - Я сумніваюся, що процесор що-небудь знає про стек, тому що ми маніпулюємо ним за допомогою subbing (виділення), натискання та вискакування. Отож, тут ми називаємо конвенції, які пояснюють, як ми повинні використовувати стек.
Віктор Полевой

78

Якщо ви дуже добре розумієте стек, то зрозумієте, як працює пам'ять у програмі, і якщо ви розумієте, як працює пам'ять у програмі, ви зрозумієте, як зберігається функція в програмі, і якщо ви розумієте, як зберігається функція в програмі, ви зрозумієте, як працює рекурсивна функція і якщо ви розумієте, як працює рекурсивна функція, ви зрозумієте, як працює компілятор, і якщо ви зрозумієте, як працює компілятор, ваш розум буде працювати як компілятор, і ви легко налагодите будь-яку програму

Дозвольте мені пояснити, як працює стек:

Спочатку ви повинні знати, як представлені функції в стеці:

Купа зберігає динамічно виділені значення.
Стек зберігає значення автоматичного розподілу та видалення.

введіть тут опис зображення

Розберемося на прикладі:

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)

Тепер зрозумійте частини цієї програми:

введіть тут опис зображення

Тепер давайте розберемося, що таке стек і що це частини стека:

введіть тут опис зображення

Виділення стека:

Пам’ятайте одне: якщо умова повернення будь-якої функції задовольняється, незалежно від того, завантажила вона локальні змінні чи ні, вона негайно повернеться із стека разом із рамкою стека. Це означає, що всякий раз, коли будь-яка рекурсивна функція задовольняє базову умову, і ми ставимо повернення після базової умови, базова умова не чекатиме завантаження локальних змінних, які знаходяться в іншій частині програми. Він негайно поверне поточний кадр із стека, за яким наступний кадр тепер знаходиться в записі активації.

Дивіться це на практиці:

введіть тут опис зображення

Розподіл блоку:

Тому тепер, коли функція стикається з оператором return, вона видаляє поточний кадр зі стека.

Повертаючись із стека, значення повертаються у зворотному порядку, у якому вони були розподілені у стеці.

введіть тут опис зображення


3
стек росте вниз, а купа росте вгору, ви перевернули їх у своїй діаграмі. ПРАВИЛЬНА ДІАГРАМА ТУТ
Рафаель

@Rafael Вибачте за плутанину, я говорив про напрямок зростання, я не говорив про напрямок зростання стека. Існує різниця між напрямком росту та напрямком росту стека. Дивіться тут stackoverflow.com/questions/1677415 / ...
Аадітья Ura

2
Рафаель має рацію. Також перша картинка неправильна. Замініть його чимось іншим (шукайте google картинки для "купи купи").
Нікос

Отже, якщо я правильно розумію, у вашій третій діаграмі є 3 кадри стека, оскільки hello()рекурсивно викликав, hello()який потім (знову) рекурсивно викликав hello(), а глобальний кадр - це оригінальна функція, яка називається першою hello()?
Енді Дж

1
Куди нас ведуть посилання ?? Як серйозну стурбованість безпекою, ці посилання слід усунути якнайшвидше.
Шиваншу

45

Швидке обгортання. Можливо, хтось має краще пояснення.

Стек виклику складається з 1 або багатьох декількох кадрів стека. Кожному фрейму стека відповідає виклик функції або процедури, яка ще не закінчилася поверненням.

Для використання кадру стека нитка зберігає два вказівники, один називається покажчиком стека (SP), а другий називається покажчиком кадру (FP). SP завжди вказує на "верх" стека, а FP завжди вказує на "верх" кадру. Крім того, потік також підтримує лічильник програм (ПК), який вказує на наступну інструкцію, яку потрібно виконати.

На стеку зберігаються: локальні змінні та часові часописи, фактичні параметри поточної інструкції (процедура, функція тощо)

Існують різні умови виклику щодо очищення штабеля.


7
Не забувайте, що зворотна адреса підпрограми йде у стеку.
Тоні Р

4
Frame Pointer також є базовим покажчиком у термінах x86
peterchaula

1
Я хотів би підкреслити, що покажчик кадру вказує на початок кадру стека для втілення активної в даний час процедури.
Сервер Халілов

13

"Стек виклику складається з кадру стека ..." -  Вікіпедія

Рамка стека - це річ, яку ви кладете на стек. Це структури даних, які містять інформацію про підпрограми для виклику.


Вибачте, я не маю уявлення, як я пропустив це на вікі. Дякую. Я правильно розумію, що в динамічних мовах розмір кадру не є постійним значенням, оскільки місцеві функції функції точно не відомі?
ikostia

Розмір і характер кадру сильно залежать від архітектури машини. Насправді, сама парадигма стека викликів залежить від архітектури. Наскільки я знаю, він завжди мінливий, тому що різні виклики функцій матимуть різну кількість даних аргументів.
Тоні Р

Зауважте, що розмір кадру стека повинен знати процесор під час маніпулювання. Коли це відбувається, розмір даних вже визначається. Динамічні мови компілюються до машинного коду так само, як статичні мови, але часто робляться вчасно, щоб компілятор міг підтримувати динамічність і процесор міг працювати з "відомими" розмірами кадру. Не плутайте мови вищого рівня з машинним кодом / складанням, саме там насправді відбувається цей матеріал.
Тоні Р

Ну, але динамічні мови також мають стеки викликів, чи не так? Я маю на увазі, якщо, скажімо, Python хоче виконати якусь процедуру, дані про цю процедуру зберігаються всередині структури якоїсь інтерпретації Python, я правда? Тому я маю на увазі, що стек викликів присутній не лише на низькому рівні.
ikostia

Прочитавши трохи тієї статті вікіпедії, я виправданий (трохи). Розмір кадру стека може залишатися невідомим під час компіляції . Але до моменту, коли процесор працює зі вказівниками стека + фрейму, він повинен знати, які розміри. Розмір може бути змінним, але процесор знає розмір, це те, що я намагався сказати.
Тоні Р

5

Програмісти можуть мати питання щодо фреймів стека не в широкому терміні (що це окрема суть у стеку, яка обслуговує лише один виклик функції і зберігає зворотну адресу, аргументи та локальні змінні), але у вузькому сенсі - коли термін stack framesзгадується в контекст параметрів компілятора.

Має на увазі автор запитання чи ні, але концепція кадру стека з точки зору варіантів компілятора є дуже важливим питанням, не охопленим іншими відповідями тут.

Наприклад, компілятор Microsoft Visual Studio 2015 C / C ++ має такий варіант, пов’язаний із stack frames:

  • / Oy (опускання кадру-покажчика)

GCC мають наступне:

  • -fomit-frame-pointer (Не тримайте покажчик кадру в реєстрі для функцій, які не потребують. Це дозволяє уникнути інструкцій щодо збереження, налаштування та відновлення покажчиків кадру; це також робить додатковий реєстр доступним у багатьох функціях )

Компілятор Intel C ++ має такі характеристики:

  • -fomit-frame-pointer (Визначає, чи використовується EBP в якості регістра загального призначення в оптимізаціях)

який має такий псевдонім:

  • / Ой

У Delphi є такий варіант командного рядка:

  • - $ W + (Створення фреймів стеків)

У цьому конкретному сенсі, з точки зору компілятора, стековий кадр - це лише код входу та виходу для підпрограми , який підштовхує якір до стеку - який також може використовуватися для налагодження та для обробки винятків. Інструменти для налагодження можуть сканувати дані стека та використовувати ці якорі для зворотного call sitesпроходження , розміщуючи в стеку, тобто для відображення назв функцій у тому порядку, який вони були названі ієрархічно. Для архітектури Intel це - push ebp; mov ebp, espабо enterдля входу, mov esp, ebp; pop ebpабо leaveдля виходу.

Ось чому дуже важливо зрозуміти програмісту, що таке кадр стека, коли мова йде про параметри компілятора - адже компілятор може контролювати, генерувати цей код чи ні.

У деяких випадках кадр стека (код входу та виходу для підпрограми) може бути опущений компілятором, і до змінних буде доступ безпосередньо через вказівник стека (SP / ESP / RSP), а не зручний базовий покажчик (BP / ESP / RSP). Умови опущення рамки стека, наприклад:

  • функція - це функція аркуша (тобто кінцева сутність, яка не викликає інших функцій);
  • немає спроб / нарешті або спробувати / за винятком або подібних конструкцій, тобто не використовуються винятки;
  • ніякі підпрограми не викликаються з вихідними параметрами на стеку;
  • функція не має параметрів;
  • функція не має вбудованого коду складання;
  • тощо ...

Опущення кадрів стека (код входу та виходу для звичайної програми) може зробити код меншим та швидшим, але це також може негативно вплинути на здатність налагоджувачів відновлювати дані в стеку та відображати їх програмісту. Це варіанти компілятора, які визначають, за яких умов функція повинна мати код входу та виходу, наприклад: (a) завжди, (b) ніколи, (c) за потреби (із зазначенням умов).


-1

Кадр стека - це упакована інформація, пов'язана з викликом функції. Ця інформація, як правило, включає аргументи, передані до функції, локальні змінні та куди повернутися після закінчення. Запис активації - інша назва кадру стека. Макет кадру стека визначається в ABI виробником, і кожен компілятор, що підтримує ISA, повинен відповідати цьому стандарту, однак схема компонування може залежати від компілятора. Як правило, розмір кадру стека не обмежений, але існує концепція, яка називається "червона / захищена зона", яка дозволяє системним викликам ... тощо виконувати, не заважаючи кадру стека.

SP завжди є, але на деяких ABI (наприклад, ARM та PowerPC) FP необов’язковий. Аргументи, які потрібно було розмістити на стеку, можна компенсувати лише за допомогою SP. Чи буде створений кадр стека для виклику функції чи ні, залежить від типу та кількості аргументів, локальних змінних та способу доступу до локальних змінних. У більшості ISA, по-перше, використовуються регістри, і якщо аргументів більше, ніж регістри, призначені для передачі аргументів, вони розміщуються в стеку (наприклад, x86 ABI має 6 регістрів для передачі цілих аргументів). Отже, іноді деяким функціям не потрібен кадр стека, щоб розміщувати його на стеку, просто повернення адреси висувається на стек.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.