Яка різниця між "статичною" та "статичною вбудованою" функцією?


123

ІМО обидва роблять функцію мати область лише перекладацького блоку.

Яка різниця між "статичною" та "статичною вбудованою" функцією?

Чому слід inlineставити у заголовок файл, а не у .cфайл?

Відповіді:


109

inlineдоручає компілятору спробувати вставити вміст функції в код виклику, а не виконувати фактичний виклик.

Для невеликих функцій, які часто викликаються, які можуть значно змінити продуктивність.

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

наприклад:

static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};

Цей щільний цикл виконуватиме виклик функції під час кожної ітерації, а вміст функції насправді значно менший, ніж код, який потрібно ввести компілятору для виконання виклику. inlineпо суті, доручить компілятору перетворити код вище в еквівалент:

 int i;
 ....
 for (i=0; i<999999; i = i+1) { /* do something here */};

Пропуск фактичного виклику функції та повернення

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

staticстосується сфери застосування. У C це означає, що функцію / змінну можна використовувати лише в межах одного блоку перекладу.


4
Ні, staticстосується сфери застосування. У C це означає, що функцію / змінну можна використовувати лише в межах одного блоку перекладу.
littleadv

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

13
@VoidStar Насправді static(з або без inline) може бути в шапці ідеально добре, не бачте причини, чому б ні. Шаблони призначені для C ++, це питання стосується C.
littleadv

2
@littleadv: Основна причина розміщення визначень функцій у файлах заголовків полягає в тому, щоб зробити їх непомітними, тому маркування їх явно inlineє хорошим стилем, imo
Крістоф

9
Насправді inlineне вказує компілятору робити будь-які спроби вбудовування. Він просто дозволяє програмісту включити функціональне тіло в декілька блоків перекладу без порушення ODR. Побічним ефектом цього є те, що це дає можливість для компілятора, коли він буде вбудовувати функцію, насправді це зробити.
Руслан

96

За замовчуванням визначення вбудованого тексту є дійсним лише в поточній одиниці перекладу.

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

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

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

Оскільки компілятор вільний вбудовувати (а не вбудовувати) будь-яку функцію, визначення якої видно в поточному блоці перекладу (і, завдяки оптимізації часу зв’язку, навіть у різних одиницях перекладу, хоча стандарт C насправді не враховує що) для більшості практичних цілей немає різниці між визначеннями staticта static inlineфункціями.

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

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

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

Взагалі, я використовую лише визначення static inlineфункцій та static constоб'єктів на додаток до externдекларацій у заголовках.

Я ніколи не писав inlineфункції з класом зберігання, відмінним від static.


8
Це правильна відповідь. Будь-яка відповідь, яка говорить про те inline, ніби вона насправді застосовується до вкладок, є оманливою і, мабуть, невірною. Жоден сучасний компілятор не використовує його як підказку для вбудованого чи потрібного для того, щоб увімкнути вбудовану функцію.
Tyg13

1
схвалено "використовувати конвенцію для позначення визначення статичних функцій в заголовках в рядку".
Джон З. Лі

Я читаю всю вашу відповідь, і все ще не розумію смислової різниці між staticі static inline. Вони обидва роблять це визначення невидимим для інших перекладацьких одиниць. Отже, що було б розумним приводом писати static inlineзамість static?
користувач541686

21

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

Тому я схильний вважати, що staticслід використовувати в одиницях перекладу і користуватися додатковим компілятором перевірки, щоб знайти невикористані функції. І їх static inlineслід використовувати у файлах заголовків для надання функцій, які можуть бути вбудовані (через відсутність зовнішньої зв'язку) без видачі попереджень.

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


1
Ммм, все ще є warning: unused function 'function' [clang-diagnostic-unused-function]для static inlineфункції при складанні clang-tidy(v8.0.1), який використовується в іншій одиниці трансляції. Але, безумовно, це одне з найкращих пояснень та причин поєднання static& inline!
DrumM

6

У C staticозначає, що функція або змінна, яку ви визначаєте, може використовуватися лише в цьому файлі (тобто блоці компіляції)

Отже, static inlineозначає вбудовану функцію, яку можна використовувати лише в цьому файлі.

Редагувати:

Одиницею компіляції має бути Блок перекладу


2
Або у вигадливих словах: вона має внутрішні зв’язки.
К-бал

@AlokSave: Чи є різниця між одиницею компіляції та одиницею перекладу ? Якщо так, що є більш підходящим у контексті мови C ++?
legends2k

Я вважаю the compile unit, що я написав помилково, такого немає, власне термінологіяtranslation unit
shengy

Ваша відповідь не є повною, оскільки вона в основному використовується у файлах заголовків, в одиницях перекладу.
DrumM

5

Одна відмінність, що не на мовному рівні, а на популярному рівні реалізації: певні версії gcc видалять невибрані static inlineфункції з виводу за замовчуванням, але зберігатимуть звичайні staticфункції, навіть якщо їх не визначають. Я не впевнений , які версії це відноситься, але з практичної точки зору це означає , що вона може бути гарною ідеєю , щоб завжди використовувати inlineдля staticфункцій в заголовках.


Що з використанням inlineвизначення? Ви також маєте на увазі не використовувати його для externфункцій?
new_perl

Чи все-таки це справедливо для останньої версії GCC? Ваша відповідь була б набагато цікавішою, якби ви подали приклад і вказали, у якій версії GCC це зробити.
Z boson

@Zboson: Наразі у мене немає такої інформації, і зараз не маю часу встановити та перевірити багато версій gcc, але я погоджуюсь, що це була б корисна інформація. Ви, ймовірно, могли виявити, коли gcc вперше почав оптимізувати невикористані статичні функції / об'єкти, переглянувши історію attribute((used))та її використання, щоб дозволити asm посилатися на інакше невіднесені staticфункції та дані.
R .. GitHub СТОП ДОПОМОГАТИ ДВІ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.