Основи програмування на С ++ для початківців

Встроенные функции (inline-функции)

Inline функції вельми цікавий рудимент, дістався сучасному світові з уже далеких бандитських 90-х. Коли процвітав асемблер, Сі компілював дуже компактні і маленькі програми, коли процесори були слабенькими (в порівнянні з тим, що зараз в мобілки ставлять наприклад) і час виконання коду цінувалося на вагу золота. Цей тип функцій взагалі-то використовувався не тільки в Сі, і в той лихий час виправдовував себе.

Я вважаю, не для кого не секрет, що стародавні комп'ютери вимагали при написанні ПЗ для важких обчислень досить таки серйозного підходу з позиції програміста. Викручуватися і економити доводилося на всьому, інакше час роботи програми збільшувалася в рази. Це зараз ми ганяємо гігабайтні іграшки не особливо скаржачись на швидкість роботи. У той час це було надзвичайно критично, і одним із способів скоротити час роботи, як раз були в лінію (встроенные) функции. Зараз я спробую більш менш доступно розповісти чому.

Итак, що з себе представляє звичайна функція? Візьмемо наприклад простий приклад – обчислення факторіала.

Досить прості обчислення факторіала (5!) в цикле for, і повернення результату з функції. С ++ розцінює цю функцію як якийсь блок операцій, згрупований в окремий блок. Блок цей після компіляції поміщається в осередку пам'яті одного разу в коді, і тіло функції (цикл в даному випадку) ніде більше в компільованою програмі не повторюється. Все гарно – виходить якийсь ділянку пам'яті, належав програмі, на який процесор при необхідності перескакує з того місця, де знаходить виклик.

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

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

Якщо описати наш факторіал так:

то замість

ми отримаємо розворот функції в набір операторів:

як нібито самі в коді написали в цьому місці.

Відповідно код типу:

перетвориться в

Якщо міряти філософськи – кількість коду з в лінію функцією збільшилася. Замість одного рядка виклику функції її тіло, підставлену замість виклику , дало цілих 6 строк. Так само буде і в компільованою програмі – кількість операторів зросте багаторазово – на стільки, скільки операторів в тілі функції і скільки разів її вписали в програму.

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

Де тут вигода запитаєте ви? Економиться час процесора на стрибки з місця виклику в тіло функції. Якщо функція величезна і використовується в декількох місцях, те в лінію виходить не зовсім вигідно. Однак, якщо функція (тіло її) маленьке, з мінімальною кількістю операторів, вирішують завдання, за старих часів було зручніше відмовитися від стрибка і просто підставити їх в потрібне місце, як ніби сам програміст там їх описав.

Як би там не було, в побутових умовах та ще й на сучасних комп'ютерах, программы, використовують в лінію підстановку тіла функції замість виклику, не дають особливих переваг. Тому використовувати цей вид функції доводиться досить рідко. ІМХО, йому місце в музеї слави. хоча, щоб бути до кінця чесним, такий підхід дає свої плоди тим, хто програмує контролери, процесори та інші залізяки. Але там свої особливості і свій підхід, і в це заглиблюватися зараз не варто. використовувати вбудовану функцію (в лінію функцію) чи ні – вирішувати самому програмісту. Від себе можу додати тільки одне – не варто робити це там, де цього не потрібно за завданням.

14 думки про "Встроенные функции (inline-функции)

  1. > Тому використовувати цей вид функції доводиться досить рідко.

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

    На прикладі класу, визначального 2D-точку (на площині):
    class point {
    private:
    float x, y;
    public:
    ...
    float operator -( const point& p ) { // расстояние 2-х 2D
    float dx = ( x - p.x ), dy = ( y - p.y );
    return sqrtf( dx * dx + dy * dy );
    }
    };

    І альтернативне 2-е визначення, дуже схоже:
    class point {
    private:
    float x, y;
    public:
    ...
    float operator -( const point& p ); // расстояние 2-х 2D
    };

    float point::operator -( const point& p ) {
    float dx = ( x - p.x ), dy = ( y - p.y );
    return sqrtf( dx * dx + dy * dy );
    };

    У 1-му варіанті відстань між 2-ма точками буде всюди обчислюватися inline, а в другому – викликом функції-методу.

    1. Це вже турбота компілятора. Мається на увазі самому програмісту рідко доводиться в побутових умовах використовувати цей вид функцій.

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

      2. Принцип інлайн не змінюється в залежності від того, в ООП його застосовують або в функціоналки )
        До чого такі ускладнення теорії? Я не проти уточнень, але тоді потрібна ще одна стаття, описує різницю між тим і цим випадками. Немає ніякої потреби заважати всю теорію в купу – вийде той же самий MSDN.

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

    Приклад – визначте функцію факторіала так:
    inline unsigned long long fact3( int n ) {
    return 1 == n ? 1 : n * fact3( n - 1 );
    }

    Тут inline не зіграє ніякої ролі.

    1. Ну то ж саме. У сучасному Сі компілятор сам вирішує. У своєму DLYA 8086 или 80286 не всі компілятори так оптимізували.

  3. Ще одна “дрібниця”: функції з кваліфікаторів inline чудово працюють, але до тих пір, поки визначення функції і виклик знаходяться в одному файлі коду. При зростанні проекту, варто розділити код на кілька файлів (роздільна компіляія з подальшим зв'язуванням об'єктних файлів), і це створить величезні проблеми з пошуком помилки: inline функціонально непридатні для зовнішнього зв'язування.

    в лінію – це визначник макроозначення, і вони непридатні для зовнішнього зв'язування (пов'язаний).

  4. > Цей тип функцій взагалі-то використовувався не тільки в Сі, і в той лихий час виправдовував себе.

    У стандарті мови C взагалі немає ключового слова inline, там подібні речі реалізуються через параметризовані макроси #define.
    У деяких пізніх компіляторах C inline включено, але тільки для пддержанія совместімсоті з C ++.
    Тому в принципі невірно говорити, що inline запозичене з C, це – чисто C ++ придбання.
    Тому я б ось те “хвацькі” початок викинув.

    1. А я не натякав на стандарт. Я натякав на МВР. У Паскалі теж такі функції існували. Та й в бейсике здається було щось подібне в пізніх його видах.

      1. > Цей тип функцій взагалі-то використовувався не тільки в Сі

        У мові C не було ключового слова inline від моменту, коли його в 1969 р. почав формулювати Денис Рітчі, і майже до 2000-х років.
        Весь цей час якщо слів inline з'явилося програмі C, воно б викликало синтаксичну помилку.

  5. До питання сумісності C і C ++ … щодо inline:

    Якщо компілювати код як C, але з ключем -std = c89 (т.е. ANSI стандарт 1989р.), то на inline просто буде синтаксична помилка. І на всіх попередніх стандартах мови C.
    Використання inline в C допустить тільки компілятор з опцією -std = c99, т.е. таке ключове слово допускається стандартом C тільки після 1999р.

  6. Взагалі то, стаття про inline функції, на відміну від більшості статей сайту – невдала. Мені здається, що її слід було б злегка скорегувати, додавши і виправивши з урахуванням зазначених позицій.

    1. Я, коли її писав, не бажав вдаватися в особливі подробиці, щоб не загороджувати ними саму суть. Не дарма в інтернеті є правило “многабукаф”, яке часто роздмухує контент в салат Ой-Лівьйо.

Залишити коментар до Stilet Скасувати відповідь

Ваша електронна адреса не буде опублікований. Обов'язкові поля позначені * *