Сторінка
1
1. Точка повернення Місце в програмі, що описує дію, якою вона продовжується по закінченні виконання виклику підпрограми, називається точкою повернення з підпрограми. Отже, коли виконання програми доходить до виклику підпрограми, запам'ятовується точка повернення з неї, та вказівка на цю точку зберігається до закінчення виконання виклику. Потім за цією вказівкою продовжується виконання програми саме з точки повернення. Вказівка точки повернення займає частину локальної пам'яті процесу виконання виклику підпрограми. Що ще знаходиться в цій пам'яті, ми скажемо трохи нижче. Точка повернення з процедури – це позначення дій, виконуваних після її виклику. Це може бути наступний за її викликом оператор, як у програмі sort31. Або умова завершення чи продовження циклу, якщо виклик записаний останнім у тілі циклу. Після виклику функції може застосовуватися операція до значення, що повертається з виклику, або обчислюватися наступний операнд у виразі, або обчислене значення може використовуватися в операторі. Наприклад, у програмі minimdis із підрозділу 3.3 результат виклику функції присвоюється змінної dd. У програмі simpi із прикладу 4.7 виклик функції issimple записана як умова в if-операторі, і після виклику визначається, яка з гілок повинна бути виконана. При обчисленні виразу sqr(x)+sqr(y) спочатку один за одним виконуються виклики функції sqr, потім повернуті з них значення додаються. Конкретний вигляд точки повернення в машинній програмі ми не уточнюємо.
2. Локальна пам'ять процесу виконання виклику підпрограми У підрозділі 3.4 ми вже говорили про те, що параметрам-значенням підпрограми при виконанні її виклику зіставляються власні ділянки пам'яті, тобто змінні. У блоці підпрограми можуть бути означені власні імена змінних – ділянки пам'яті зіставляються їм так само. Крім того, є ділянка пам'яті з точкою повернення. Сукупність усіх цих ділянок пам'яті називається локальною пам'яттю процесу виконання виклику підпрограми. Її часто неточно називають локальною пам'яттю підпрограми. Будемо грішити цим і ми. Змінні в ній також називаються локальними. Якщо підпрограма є функцією, то до її локальної пам'яті додається змінна для збереження значення, що повертається з її виклику. Можна сказати, що ця змінна ставиться у відповідність імені функції. Таким чином, наприклад, локальна пам'ять процедури swap із підрозділу 3.4 (у її остаточному вигляді) складається з єдиної змінної, зіставленої імені t, а пам'ять функції dd із програми minimdis (підрозділ 3.3) – із змінних, зіставлених іменам xx1, yy1, xx2, yy2 і dd. А також указівки на точку повернення.
3. Підстановка аргументів на місце параметрів Перед тим, як починається виконання операторів тіла підпрограми, для неї виділяється локальна пам'ять і в ній запам'ятовується точка повернення. Потім обчислюються значення тих аргументів у виклику, які відповідають параметрам-значенням. Ці значення присвоюються локальним змінним, які поставлено у відповідність параметрам-значенням. Присвоювання значень аргументів, тобто копіювання їх у локальну пам'ять, називається підстановкою аргументів на місце параметрів за значенням. Підстановка аргументів на місце параметрів-змінних відбувається зовсім іншим шляхом. Нагадаємо, що таким аргументом може бути тільки ім'я змінної (або інше її позначення, наприклад, у вигляді поля структури). Ніякого обчислення її значення, тобто розіменування аргументу, не відбувається. Ця змінна, тобто ділянка пам'яті, ставиться у відповідність параметрові підпрограми. Це називається підстановкою аргументу на місце параметра за посиланням, або за адресою. У результаті такої підстановки ім'я параметра-змінної перетворюється на вказівку на ділянку пам'яті, яка поставлена у відповідність аргументу. Вказівка на ділянку пам'яті називається посиланням на неї, або її адресою. Як саме вказівка на аргумент стає відомою у процесі виконання підпрограми, ми не уточнюємо. Для цього нам довелося б занадто глибоко забратися в устрій комп'ютера і машинної мови.
4. Процес виконання виклику підпрограми Опишемо процес виконання виклику підпрограми (вона називається такою, що викликається, а програма або підпрограма, що містить її виклик – такою, що викликає).
1. Виділяється локальна пам'ять підпрограми, що викликається, а точніше, пам'ять процесу виконання виклику.
2. Обчислюється й запам'ятовується в локальній пам'яті підпрограми, що викликається, точка повернення в ту, що викликає.
3. Обчислюються значення аргументів, відповідних параметрам-значенням, і посилання на пам'ять аргументів, відповідних параметрам-змінним. Виконується підстановка аргументів.
4. Лише після цього виконуються оператори тіла підпрограми. Зокрема, у локальній пам'яті запам'ятовується значення, що повертається з виклику функції.
5. Значення змінної з ім'ям функції копіюється з локальної в пам'ять програми, що викликає, або підпрограми, відведену під значення, що повертається. Процес виконання виклику підпрограми закінчується і продовжується виконання програми чи підпрограми, що викликає, із точки повернення. Як уже говорилося в підрозділі 3.4, усяка зміна значення параметра-змінної є насправді зміною відповідного аргументу. Після закінчення виклику результати обробки параметрів-змінних залишаються в аргументах, чого не можна сказати про параметри-значення. Змінні локальної пам'яті підпрограми не зіставлені ніяким іменам підпрограми, у якій записано виклик. А це значить, що після закінчення виконання виклику локальна пам'ять стає недоступною в підпрограмі, що викликає, і можна вважати, що вона звільняється. А раз так, то її можна наново зайняти під локальні змінні при виконанні наступного виклику якої-небудь підпрограми. І останнє зауваження про те, як при написанні підпрограми вибирати вид параметра – параметр-значення чи параметр-змінна. Якщо після виклику підпрограми повинно використовуватися нове значення аргументу, одержане при виконанні виклику, то відповідний параметр слід означити як параметр-змінну. Наприклад, як параметри в остаточному варіанті процедури swap із підрозділу 3.4. Якщо після виклику підпрограми використовується старе значення аргументу або аргументом може бути довільний вираз, то йому має відповідати параметр-значення. Як параметр функції issimple з прикладу 4.7. З останнього правила, утім, є винятки, пов'язані з параметрами та аргументами, що є масивами. Про це йтиметься в підрозділі 12.1. Приклад 1. Розглянемо імітацію виконання програми з викликами підпрограм. Як і в підрозділі 7.1, будемо позначати локальну змінну, наприклад, L підпрограми F, як F.L, відрізняючи її від однойменної змінної програми. Вказівку точки повернення позначимо буквами ТП. Процес виконання програми program nested ( input, output ); var a, b : integer; function f ( x : integer ) : integer; begin x := x + 1; f := x end; function g (var x : integer ) : integer; begin x := x div 2; g := x end; begin a := 12; b := f ( g ( a ) ) end. відобразимо такою таблицею:
Що виконується |
Стан пам'яті | ||
a b | |||
a := 12 |
12 ? | ||
починається b := f(g(12)) |
12 ? | ||
виклик f(g(12)) |
12 ? |
f. x f. f ТП | |
12 ? |
? ? b:= | ||
починається f. x := g(12) |
12 ? |
? ? b:= | |
виклик g(12) |
g. x ? |
? ? b:= |
g. g ТП |
g. x := 12 |
12 ? |
? ? b:= |
? f. x:= |
g. x := g. X div 2 |
6 ? |
? ? b:= |
? f. x:= |
g. g := g. X |
6 ? |
? ? b:= |
6 f. x:= |
повернення з g |
6 ? |
? ? b:= |
6 f. x:= |
закінчення f. x := g(12) |
6 ? |
6 ? b:= | |
f. x := f. x + 1 |
6 ? |
7 ? b:= | |
f. f := f. X |
6 ? |
7 7 b:= | |
повернення з f |
6 ? |
7 7 b:= | |
закінчення b := f(g(12)) |
6 7 |