6.7.4 Специфікатори функцій
Нова особливість C99:inline
ключове слово, запозичені з C ++, є функція-специфікатор , який може бути використаний тільки в оголошенні функції. Це корисно для оптимізації програми, яка вимагає, щоб визначення функції було видно на місці виклику. (Зверніть увагу, що Стандарт не намагається вказати характер цих оптимізацій.)
Видимість забезпечується, якщо функція має внутрішню зв'язок або якщо вона має зовнішню зв'язок, а виклик знаходиться в тій самій одиниці перекладу, що і зовнішнє визначення. У цих випадках наявність
inline
ключового слова в оголошенні або визначенні функції не має жодного ефекту, окрім зазначення переваги щодо того, що виклики цієї функції повинні бути оптимізовані на відміну від викликів інших функцій, оголошених без inline
ключового слова.
Видимість є проблемою для виклику функції із зовнішнім зв'язком, коли виклик знаходиться в іншій одиниці перекладу, ніж визначення функції. У цьому випадку inline
ключове слово дозволяє блоку перекладу, що містить виклик, також містити локальне або вбудоване визначення функції.
Програма може містити одиницю перекладу із зовнішнім визначенням, одиницю перекладу з вбудованим визначенням та одиницю перекладу з декларацією, але без визначення функції. Дзвінки в останньому блоці перекладу використовуватимуть зовнішнє визначення, як зазвичай.
Вбудоване визначення функції вважається іншим визначенням, ніж зовнішнє визначення. Якщо виклик якоїсь функції func
із зовнішнім зв'язком відбувається там, де видно вбудоване визначення, поведінка така сама, як якщо б виклик здійснювався до іншої функції, скажімо
__func
, з внутрішнім зв'язком. Відповідна програма не повинна залежати від того, яка функція викликається. Це вбудована модель у Стандарті.
Відповідна програма не повинна покладатися на реалізацію з використанням вбудованого визначення, а також не може покладатися на реалізацію з використанням зовнішнього визначення. Адреса функції - це завжди адреса, що відповідає зовнішньому визначенню, але коли ця адреса використовується для виклику функції, може використовуватися вбудоване визначення. Тому наступний приклад може поводитися не так, як очікувалося.
inline const char *saddr(void)
{
static const char name[] = "saddr";
return name;
}
int compare_name(void)
{
return saddr() == saddr(); // unspecified behavior
}
Оскільки реалізація може використовувати вбудоване визначення для одного із викликів saddr
та використовувати зовнішнє визначення для іншого, операція рівності не гарантується оцінювати як 1 (істина). Це показує, що статичні об'єкти, визначені у вбудованому визначенні, відрізняються від відповідного їм об'єкта у зовнішньому визначенні. Це мотивувало обмеження навіть щодо визначення не- const
об'єкта цього типу.
Вбудовування було додано до стандарту таким чином, що його можна реалізувати за допомогою існуючої технології компонування, а підмножина вкладання C99 сумісна з C ++. Це було досягнуто завдяки вимогам, щоб точно одна одиниця перекладу, що містить визначення вбудованої функції, була вказана як та, яка забезпечує зовнішнє визначення функції. Оскільки ця специфікація складається просто з оголошення, в якому або бракує inline
ключового слова, або містить обидва inline
таextern
воно також буде прийняте перекладачем на C ++.
Вбудовування в C99 розширює специфікацію C ++ двома способами. По-перше, якщо функція оголошена
inline
в одній одиниці перекладу, її не потрібно оголошувати inline
в будь-якій іншій одиниці перекладу. Це дозволяє, наприклад, функцію бібліотеки, яка повинна бути вбудована в бібліотеку, але доступна лише через зовнішнє визначення в іншому місці. Альтернатива використання функції обгортки для зовнішньої функції вимагає додаткового імені; і це також може негативно вплинути на ефективність роботи, якщо перекладач насправді не виконує вбудовану заміну.
По-друге, вимога про те, що всі визначення вбудованої функції мають бути “абсолютно однаковими”, замінюється вимогою про те, що поведінка програми не повинна залежати від того, реалізований виклик із видимим вбудованим визначенням, або зовнішнє визначення функція. Це дозволяє вбудованому визначенню бути спеціалізованим для використання в певній одиниці перекладу. Наприклад, зовнішнє визначення функції бібліотеки може включати перевірку аргументів, яка не потрібна для викликів, здійснених з інших функцій тієї самої бібліотеки. Ці розширення дійсно пропонують деякі переваги; а програмісти, які стурбовані сумісністю, можуть просто дотримуватися більш суворих правил С ++.
Зауважте, що реалізація не підходить для надання вбудованих визначень стандартних функцій бібліотеки у стандартних заголовках, оскільки це може порушити деякий застарілий код, який повторно оголошує стандартні функції бібліотеки після включення їх заголовків. inline
Ключове слово призначене тільки для надання користувачам стерпним способом , щоб запропонувати вбудовування функцій. Оскільки стандартні заголовки не повинні бути переносними, реалізації мають інші варіанти, подібні до:
#define abs(x) __builtin_abs(x)
або інші непереносні механізми для включення стандартних функцій бібліотеки.