6.9 Встроенная функция так же быстра, как макрос
Объявив функцию встроенной, вы можете указать GCC ускорить вызовы этой функции. Один из способов добиться этого — встроить код функции в код вызывающих её функций. Это ускоряет выполнение за счёт устранения накладных расходов на вызов функции; кроме того, если значения каких-либо фактических аргументов являются константами, известные значения могут позволить выполнить упрощения во время компиляции, так что включать весь код встроенной функции не потребуется. Влияние на размер кода предсказать сложнее: встраивание функции может как увеличить, так и уменьшить размер объектного кода — в зависимости от конкретного случая. С помощью параметра -finline-functions можно также указать GCC попытаться встроить в вызывающий код все функции, которые «достаточно просты».
GCC реализует три различных семантики объявления функции встроенной. Одна доступна при использовании -std=gnu89 или -fgnu89-inline, а также когда атрибут gnu_inline присутствует во всех объявлениях встроенной функции; другая — при использовании -std=c99, -std=gnu99 или параметра для более поздней версии C (без -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. Если есть вызов, который не удалось встроить, функция компилируется в ассемблерный код обычным образом. Функция также должна компилироваться обычным образом, если программа обращается к её адресу, поскольку такой вызов невозможно встроить.
Обратите внимание, что некоторые конструкции в определении функции могут сделать её неподходящей для подстановки встраиванием. К ним относятся: функции с переменным числом аргументов, использование alloca, вычисляемого перехода (см. Метки как значения), нелокального перехода, вложенных функций, setjmp, __builtin_longjmp, а также __builtin_return или __builtin_apply_args. Параметр -Winline выдаёт предупреждение, если функцию, помеченную inline, не удалось встроить, и указывает причину сбоя.
В соответствии с требованиями ISO C++ GCC считает функции-члены, определённые внутри тела класса, помеченными как встроенные, даже если они явно не объявлены с ключевым словом inline. Это поведение можно отключить с помощью -fno-default-inline; см. Параметры управления диалектом C++.
Если оптимизация не выполняется, GCC не встраивает функции, если только вы не укажете для функции атрибут ‘always_inline’, например:
/* Prototype. */
inline void foo (const char) __attribute__((always_inline));
Остальная часть этого раздела относится только к встраиванию в GNU C90.
Если встроенная функция не является static, компилятор должен предполагать, что её могут вызывать из других исходных файлов. Поскольку глобальный символ может быть определён в программе только один раз, функцию нельзя определять в других исходных файлах, поэтому содержащиеся там вызовы невозможно встроить. Таким образом, невстроенная функция static всегда компилируется отдельно обычным образом.
Если в определении функции указаны одновременно inline и extern, определение используется только для встраивания. Функция ни в коем случае не компилируется отдельно, даже если вы явно обращаетесь к её адресу. Такой адрес становится внешней ссылкой, как если бы вы только объявили функцию, но не определили её.
Такое сочетание inline и extern почти эквивалентно макросу. Для его использования поместите определение функции с этими ключевыми словами в заголовочный файл, а ещё одну копию определения (без inline и extern) — в файл библиотеки. Определение в заголовочном файле приводит к встраиванию большинства вызовов функции. Если останутся вызовы этой функции, они будут ссылаться на единственную копию в библиотеке.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-15.3.0/gcc/Inline.html