6.7.4 Спецификаторы функций
Новая функция C99: ключевое слово inline
, адаптированное из С++, является спецификатором функции, который может использоваться только в объявлениях функций. Это полезно для оптимизации программ, которые требуют определение функции, которая должна быть видимой в месте вызова. (Обратите внимание, что стандарт не пытается указать природу этих оптимизаций.)
Видимость гарантируется, если функция имеет внутреннюю связь, или если она имеет внешнюю связь и вызов находится в той же единице перевода, что и внешнее определение. В этих случаях наличие 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 совместим с С++. Это было достигнуто, если потребовать, чтобы ровно одна единица перевода, содержащая определение встроенной функции, указанный как тот, который предоставляет внешнее определение функции. Из-за этого спецификация состоит просто из объявления, которое либо не имеет ключевое слово inline
, либо содержит как inline
и extern
, он также будет принят переводчиком С++.
Вложение в C99 расширяет спецификацию С++ двумя способами. Во-первых, если объявлена функция inline
в одной единицы перевода, ее не нужно объявлять inline
в каждой другой единицы перевода. Это позволяет, например, библиотечную функцию, которая должна быть встроена в библиотеку, но доступна только через внешнее определение в другом месте. Альтернатива использования оберточной функции для внешняя функция требует дополнительного имени; и это может также отрицательно сказаться на производительности если переводчик фактически не выполняет встроенную подстановку.
Во-вторых, требование, чтобы все определения встроенной функции были "точно такими же", заменяется требованием, чтобы поведение программы не зависело от того, вызов реализуется с видимым встроенным определением или внешним определением функции. Это позволяет встроенное определение быть специализированным для его использования в конкретной единицы перевода. Например, внешнее определение функции библиотеки может включать в себя некоторую проверку аргументов, которая не нужна для вызовов, выполняемых из других функций в той же библиотеке. Эти расширения имеют некоторые преимущества; и программисты, которые обеспокоены совместимостью может просто соблюдать более строгие правила С++.
Обратите внимание, что реализациям не подходит встроенные определения стандарта библиотечные функции в стандартных заголовках, потому что это может сломать некоторый унаследованный код, который переопределяет стандартные функции библиотеки после включения их заголовков. Ключевое слово inline
предназначенный только для того, чтобы предоставить пользователям портативный способ предложить встраивание функций. Поскольку стандартные заголовки не должны быть переносимыми, реализации имеют другие варианты в соответствии с:
#define abs(x) __builtin_abs(x)
или других не переносных механизмов для встраивания стандартных библиотечных функций.