и использовать эту функцию, даже в том же файле вызов этой функции разрешается компоновщиком, а не компилятором, потому что он неявно «внешний». Но само по себе это определение не дает внешнего определения функции.
Лучшее место для размещения встроенных функций — в заголовочном файле, и объявите их static inline
. Это устраняет необходимость во внешнем определении и решает проблему компоновщика. Однако это заставляет компилятор выдавать код функции в каждой единице компиляции, которая ее использует, что может привести к раздуванию кода. Но поскольку функция встроенная, она, вероятно, в любом случае маленькая, так что обычно это не проблема.
Объявив встроенную функцию, вы можете указать GCC выполнять вызовы этой функции быстрее. Один из способов, с помощью которого GCC может добиться этого, — интегрировать код этой функции в код вызывающих ее функций. Это ускоряет выполнение, устраняя накладные расходы на вызовы функций; кроме того, если какие-либо из фактических значений аргументов являются постоянными, их известные значения могут допускать упрощения во время компиляции, так что не нужно включать весь код встроенной функции. Влияние на размер кода менее предсказуемо; объектный код может быть больше или меньше при встраивании функций, в зависимости от конкретного случая. Вы также можете указать GCC, чтобы он попытался интегрировать все «достаточно простые» функции в свои вызывающие программы с помощью опции -finline-functions
.
GCC реализует три различных семантики объявления встроенной функции. Один доступен с -std=gnu89
или -fgnu89-inline
или когда атрибут gnu_inline
присутствует во всех встроенных объявлениях, другой — когда -std=c99
, -std=c1x
, -std=gnu99
или -std=gnu1x
(без -fgnu89-inline
), а третий используется при компиляции C++.
Чтобы объявить встроенную функцию, используйте ключевое слово inline
в ее объявлении, например:
static inline int
inc (int *a)
{
return (*a)++;
}
Если вы пишете заголовочный файл для включения в программы ISO C90, напишите __inline__
вместо inline
.
Три типа встраивания ведут себя одинаково в двух важных случаях: когда ключевое слово inline
используется в функции static
, как в приведенном выше примере, и когда функция сначала объявляется без использования ключевого слова inline
, а затем определяется с помощью inline
, например:
extern int inc (int *a);
inline int
inc (int *a)
{
return (*a)++;
}
В обоих этих распространенных случаях программа ведет себя так же, как если бы вы не использовали ключевое слово inline
, за исключением ее скорости.
Когда функция одновременно является встроенной и static
, если все вызовы функции интегрированы в вызывающую программу, а адрес функции никогда не используется, то на собственный ассемблерный код функции никогда не ссылаются. В этом случае GCC фактически не выводит ассемблерный код для функции, если вы не укажете опцию -fkeep-inline-functions
. Некоторые вызовы невозможно интегрировать по разным причинам (в частности, нельзя интегрировать вызовы, предшествующие определению функции, а также рекурсивные вызовы внутри определения). Если есть неинтегрированный вызов, то функция компилируется в ассемблерный код как обычно. Функция также должна быть скомпилирована как обычно, если программа обращается к ее адресу, потому что это не может быть встроено.
Обратите внимание, что некоторые варианты использования в определении функции могут сделать ее непригодной для встроенной подстановки. Среди этих применений: использование varargs, использование alloca, использование типов данных переменного размера, использование вычисляемого перехода, использование нелокального перехода и вложенных функций. Использование -Winline
предупредит, когда функция, помеченная inline
, не может быть заменена, и укажет причину сбоя.
Согласно требованиям ISO C++, GCC считает, что функции-члены, определенные в теле класса, помечены как встроенные, даже если они явно не объявлены с помощью ключевого слова inline
. Вы можете переопределить это с помощью -fno-default-inline
.
GCC не встраивает никакие функции без оптимизации, если вы не укажете атрибут always_inline
для функции, например:
/* Prototype. */
inline void foo (const char) __attribute__((always_inline));
Оставшаяся часть этого раздела посвящена встраиванию GNU C90.
Когда встроенная функция не static
, компилятор должен предположить, что могут быть вызовы из других исходных файлов; поскольку глобальный символ может быть определен только один раз в любой программе, функция не должна быть определена в других исходных файлах, поэтому вызовы в них не могут быть интегрированы. Таким образом, встроенная функция, отличная от static
, всегда компилируется сама по себе обычным способом.
Если вы укажете и inline
, и extern
в определении функции, то определение будет использоваться только для встраивания. Ни в коем случае функция не компилируется сама по себе, даже если вы явно ссылаетесь на ее адрес. Такой адрес становится внешней ссылкой, как если бы вы только объявили функцию, а не определили ее.
Эта комбинация inline
и extern
имеет почти эффект макроса. Способ его использования состоит в том, чтобы поместить определение функции в заголовочный файл с этими ключевыми словами и поместить другую копию определения (без inline
и extern
) в файл библиотеки. Определение в заголовочном файле приведет к тому, что большинство вызовов функции будут встроенными. Если какие-либо варианты использования функции останутся, они будут ссылаться на единственную копию в библиотеке.