Урок №174. Раннє і Пізнє зв’язування

  Юрій  | 

  Оновл. 27 Вер 2021  | 

 224

Як ми вже знаємо з попередніх уроків, виконання програми в мові C++ відбувається послідовно, рядок за рядком, починаючи з функції main(). Коли компілятор зустрічає виклик функції, то точка виконання переходить до початку коду функції, що викликається. Звідки компілятор знає, що це потрібно зробити?

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

Зв’язування — це процес, який використовується для конвертації ідентифікаторів (таких як імена змінних або функцій) в адреси. Хоча зв’язування використовується як для змінних, так і для функцій, на цьому уроці ми зосередимося тільки на функціях.

Раннє зв’язування

Більшість викликів функцій, які зустрічає компілятор, є прямими викликами функцій. Прямий виклик функції — це стейтмент, який напряму викликає функцію. Наприклад:

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

Розглянемо просту програму-калькулятор, в якій використовується раннє зв’язування:

Оскільки add(a, b), subtract(a, b) і multiply(a, b) є прямими викликами функцій, то компілятор використовуватиме раннє зв’язування. Він замінить виклик add(a, b) інструкцією, яка повідомить процесору перейти до адреси add(). Те ж саме виконається і для subtract(a, b), і для multiply(a, b).

Пізнє зв’язування

У деяких програмах неможливо знати наперед, яка функція викликатиметься першою. В такому випадку використовується пізнє зв’язування (або «динамічна прив’язка»). У мові C++ для виконання пізнього зв’язування використовуються вказівники на функції. Якщо коротко, вказівник на функцію — це тип вказівника, який вказує на функцію замість змінної. Функція, на яку вказує вказівник, може викликатися через вказівник і оператор виклику функції. Наприклад, викличемо функцію add():

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

Тут ми вказуємо pFcn вказувати на функцію, яку вибере користувач. Потім через вказівник ми викликаємо функцію, яку вибрав користувач. Компілятор не може використовувати раннє зв’язування для виконання виклику функції pFcn(a, b), так як він не може наперед визначити, на яку функцію вказуватиме pFcn!

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

На наступному уроці ми розглянемо, як пізнє зв’язування використовується для реалізації віртуальних функцій.

Оцінити статтю:

1 Зірка2 Зірки3 Зірки4 Зірки5 Зірок (3 оцінок, середня: 5,00 з 5)
Loading...

Залишити відповідь

Ваш E-mail не буде опублікований. Обов'язкові поля відмічені *