Статики та динамічні засоби
Розширюючи використання функцій в режимі C для підвищення швидкості
Table of Contents
Вступ: Функція зворотного зв'язку виклик наклад
У програмі C кожен виклик функції вводить наклад: компілятор повинен натиснути аргументи на стек (або передати їх в реєстри), стрибати на тіло функції, виконувати код, а потім повернути. Для малих, часто занурених функцій, це наклад може переважати час виконання, зокрема в експлуатаційно-критичних петлях або глибоко непристойних операціях. Сучасні компілятори оптимізують агресивно, але іноді програміста повинна надати чіткі підказки для досягнення максимальної швидкості. Один такий підказок є ] ключ, який запрошує компілера замінити за допомогою себе виклику функції — метод, що називається [[Filer[Filer[Lint[Light] [[Lint[Fil] [[Flik[LT[F:] [Lt:] [Lt:] [Light] [Light] [Lt:] [Lt:] [Lt:[Fly[Fly[Fly[Fly[Fly[Fly[Fly] [Lt:] [Lt:] [Lt:] [LT
Механізм за допомогою Inline функцій
Інлайн функція проголошується з ключовим словом. Це не викликає компілятора в лінію; це припуск. Компілятор може ігнорувати його для функцій, які занадто великі, рекурсивні, або коли рівень оптимізації низькі. У C99 і пізніше стандарти, емітика були уточнені: функція, визначена в заголовку файл може бути включена в декілька одиниць перекладу, не викликаючи помилок дублювання або посилання, надані неінлайн зовнішній визначення існує десь. Це часто досягається поєднання або
- Static inline: Функція має внутрішню посилання; кожен переклад блок отримує власний копію. Це найбезпечніший і найактуальний підхід до функцій малого помічника, визначених в заголовках.
- Extern inline (C99): Визначення інлайну забезпечує тіло для нахилу, але зовнішній визначення повинен існувати окремо (зазвичай в одному файлі .c). У C11 і пізніше ця поведінка була гармоніфікована.
- Inline без статичних або ектерн: У C99, це схожий на зовнішній інлайн; в C11, зовнішні визначення потрібні тільки якщо функція не вдається. Практично є перевагою для більшості випадків використання.
Key Insight: Вхід не безкоштовний обід. Компілятор аналізує вартість-доставка Trade-off: вставки тіла функції на кожному місці виклику збільшує розмір коду (код bloat), який може зменшити ефективність кешу. Таким чином, в Інтернеті найкраще зарезервовано для невеликих, часто називають функції.
Коли Inline Функції Excel: Використовуйте випадки та кращі практики
Малі математичні операції
Функції, які виконують елементарні арифмети — такі як обчислення квадрата, затискаючи значення або перевіряють знак — є першокласними кандидатами. Наклад функції часто перевищує саму операцію. Наприклад:
static inline int clamp(int value, int low, int high) {
return (value < low) ? low : (value > high) ? high : value;
}
Функції доступу та мітатору в структурах даних
Об'єктно-орієнтовані візерунки в C часто використовують акселери і сеттери для інкапсуляції даних. Без нахилу ці тривіальні функції додають непотрібні накладні:
typedef struct {
int x, y;
} Point;
static inline int point_get_x(const Point *p) {
return p->x;
}
static inline void point_set_x(Point *p, int x) {
p->x = x;
}
Вбудовані системи та код реального часу
У середовищі з обмеженими можливостями стека і детермінатичними вимогами до термінів, в режимі реального часу функції усувають необхідність натискання / нап, зменшення як лагності, так і використання пам'яті. Однак розмір коду необхідно ретельно стежити за мікроконтролерами пам'яті.
Коли N] в Inline
- Large функції: Ввімкнення функції лінії 100+ на декількох сайтах виклику буде зблокувати бінарні і ймовірні деградації за рахунок інструкції тиску кешу.
- Рекуривні функції: Рецидив не може бути повністю ізольованим (хоча компілятор може не пропускати кілька рівнів).
- Функціони з петлями: Ввімкнення функції, що містить велику петлю, не може забезпечити суттєву користь.
- Раллі називають функції:] Надголова недбала, якщо функція називається нечасто; нахилу тільки відходи простору.
Inline Функції Versus Macros: докладний Порівняння
Перед тим як ключове слово було стандартно, C програмістів використовували макроси () для досягнення "вкління" — але макроси є текстовими замінами, не функціями. Вони приходять з серйозними недоліками:
- ]Tag: Macros ігнорувати типи. Відомий макро оцінює аргументи багаторазово, що призводить до небезпечних побічних ефектів при використанні виразів .
- Попередня: Macros зникне під час обробки; debuggers не може крок до них.
- Компанія звітів: макроси багатостатевих потреб ugly workarounds (наприклад, ).
- Назви зіткнень:] Макро розширення може заважати локальними змінними.
Інлайн функції долають всі ці питання: вони є істинними функціями з перевіркою типу, обсягом та оцінкою побічних ефектів. Вони беруть участь у регулярній системі типу і можуть бути дебуговані. Єдина теоретична перевага макросів полягає в тому, що вони можуть бути використані для , тип-генерик] операції — але C11 і C23 пропозиції є зменшенням навіть цього проміжку.
Руле великого пальця: Префер функції над макроси для будь-якої логіки, яка підходить для функції підпису. Резерв макроси тільки для простих констанцій або токенів.
Практичні приклади: Інлайн функції в дії
Приклад 1: Площа (Додатково)
static inline int square(int x) {
return x * x;
}
Якщо ви хочете, щоб ви не знали, то код стає просто на кожному сайті виклику.
Приклад 2: Перевірка Якщо Символ є цифрою
static inline int is_digit(char c) {
return c >= '0' && c <= '9';
}
Приклад 3: Швидка мін/Макс (Авоідинг Макрос)
static inline int imax(int a, int b) {
return (a > b) ? a : b;
}
На відміну від макроверсії, це оцінює і точно один раз, уникаючи подвійно-випробуваних ризиків.
Приклад 4: Біт-операції (безіони або обміни байтами)
static inline uint16_t swap_bytes(uint16_t x) {
return (x << 8) | (x >> 8);
}
Цей компілює до однієї інструкція по ARM, або обертається на x86 при інлайні.
Оптимізація компіляторів та ключів в Інтернеті
ключове слово є лише одним фактором у вирішенні інлінізації компілятора. Більшість компіляторів мають командно-лінійні прапори, які регулюють агресивність:
- GCC/Clang: дозволяє помірне нахилу; дозволяє більш агресивним нахилом. прапор може бути явно включений. Щоб сила, нахиливши певну функцію незалежно від компілятора, вінристика, скористайтеся ] з або вище.
- MSVC: ] ключове слово доступний, але не гарантує нахилу (компілятор може бути ще відмовлено від певних функцій).
Приклад з атрибутом GCC:
static inline __attribute__((always_inline)) int triple(int x) {
return x * 3;
}
Для виконання-критого коду доцільно перевірити створену збірку (наприклад, з GCC або ) для підтвердження того, що нахилу відбувався. Сучасні компілятори можуть не позначені ] на рівні високої оптимізації, а навпаки можуть ігноруватися для функцій, які призведуть до надмірного зростання коду.
Потенційні значення: Код Блаки і бінарний розмір
Встановлюючи всі виклики функції, які використовуються в багатьох місцях, можуть значно збільшити розмір текстового сегмента. Це особливо проблема:
- // Внутрішньофункціональні функції в заголовках, які розширюються в кожен переклад, який включає їх, потенційно множуючи розмір коду.
- Embedded Systems: Flash and RAM обмежена. Функція 10-байту, що використовується в 1000 місць, додає майже 10KB коду.
- Instruction cache: Код більшої кеш-памії, уповільнення всієї програми.
Щоб пом'якшити блок коду, скористайтеся тільки для дійсно малих функцій (типово 1–5 виписок). Використовуйте профільатори для виявлення гарячих функцій перед сліпим нахилом. Заміряйте як час виконання і розмір бінарних.
Функції Across C Стандарти
ключове слово було введено в C99] і далі уточнено в C11 і C17]. C23 зберігає однакову семантику з деякими додатковими поліпшеннями. історичне диференціювання між "інлайн визначення" і "зовнішня визначення" викликана конфузія. У сучасному практиці більшість проектів використовують виключно, які боковини. Цей шаблон працює з усіма C-стандартами від C99ward і уникати посилань.
Якщо ви повинні підтримувати компілятори pre-C99 (що частіше зустрічається, ви повинні повернутися до макросів або зовнішніх заголовків-навколів. В іншому випадку обіцяти як портативна і тип-safe альтернатива.
Висновки: Стратегічний інструмент в інструментарію продуктивності
Інлайн функції є зрілою, добре визначеною функцією C мови, яка, коли наноситься на ювілейно, може отримати безмірне поліпшення швидкості, використовуючи функцію виклику накладної і дозволяє крос-функціональні оптимізації. Вони перевершують макроси практично в кожному сучасному контексті. Ключ полягає в тому, щоб обмежити їх використання невеликими, гарячими функціями і переконатися в результат з профілюванням і збиранням перевірки. Поєднання відповідних прапорів компілятора, вбудовані функції роблять C код як швидко і підтримується - рідкісне поєднання в малорівневому програмування.
Для подальшого читання консультуйтеся з документацією GCC на inline функції та , вказавши запис на . Для аналізу продуктивності реального світу this ACM Queue article] детально досліджує інлінінг торгових марок.