Ответы:
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 это означает, что функция / переменная может использоваться только в одной и той же единице перевода.
static
(с или без inline
) вполне может быть в заголовке, не вижу причин, почему бы и нет. Шаблоны для C ++, этот вопрос о C.
inline
- хороший стиль, имо
inline
не инструктирует компилятор делать какие-либо попытки встраивания. Это просто позволяет программисту включать тело функции в несколько единиц трансляции без нарушения ODR. Побочным эффектом этого является то, что это дает возможность для компилятора, когда он будет встраивать функцию, на самом деле это сделать.
По умолчанию встроенное определение действительно только в текущей единице перевода.
Если класс хранилища равен extern
, идентификатор имеет внешнюю связь, а встроенное определение также предоставляет внешнее определение.
Если класс хранения равен static
, идентификатор имеет внутреннюю связь, и встроенное определение невидимо в других единицах перевода.
Если класс хранения не указан, встроенное определение видно только в текущей единице трансляции, но идентификатор все еще имеет внешнюю связь, и внешнее определение должно быть предоставлено в другой единице трансляции. Компилятор может использовать либо встроенное, либо внешнее определение, если функция вызывается в текущей единице перевода.
Поскольку компилятор может встраивать (и не встраивать) любую функцию, определение которой отображается в текущей единице перевода (и, благодаря оптимизации времени компоновки, даже в разных единицах перевода, хотя стандарт C на самом деле не учитывает that), для большинства практических целей нет разницы между определениями функций static
и static inline
.
Спецификатор inline
(как и register
класс хранилища) - это всего лишь подсказка компилятора, и компилятор может полностью ее игнорировать. Неоптимизирующие компиляторы, соответствующие стандартам, должны учитывать только свои побочные эффекты, а оптимизирующие компиляторы будут выполнять эту оптимизацию с явными подсказками или без них.
inline
и register
не бесполезны, тем не менее, поскольку они инструктируют компилятор выдавать ошибки, когда программист пишет код, который сделает оптимизацию невозможной: внешнее inline
определение не может ссылаться на идентификаторы с внутренней связью (поскольку они были бы недоступны в другой единице перевода) или определить изменяемые локальные переменные со статической продолжительностью хранения (так как они не будут разделять состояние в единицах перевода), и вы не можете брать адреса register
-квалифицированных переменных.
Лично я использую соглашение, чтобы отмечать static
определения функций в заголовках inline
, поскольку основная причина помещения определений функций в файлы заголовков - сделать их встраиваемыми.
В общем, я использую только определения static inline
функций и static const
объектов в дополнение к extern
объявлениям в заголовках.
Я никогда не писал inline
функции с классом хранения, отличным от static
.
inline
том, что он действительно применяется к встраиванию, вводит в заблуждение и, возможно, неверен. Ни один современный компилятор не использует его как подсказку для встраивания или требует его для включения встраивания функции.
static
и static inline
. Оба они делают определение невидимым для других единиц перевода. Так какой же разумный повод static inline
вместо этого писать static
?
По своему опыту работы с GCC я знаю это static
и static inline
отличается тем, как компилятор выдает предупреждения о неиспользуемых функциях. Точнее, когда вы объявляете static
функцию и она не используется в текущей единице перевода, компилятор выдает предупреждение о неиспользуемой функции, но вы можете заблокировать это предупреждение, изменив его на static inline
.
Таким образом, я склонен думать, что это static
следует использовать в единицах перевода и извлечь выгоду из дополнительных проверок компилятора для поиска неиспользуемых функций. И static inline
должен использоваться в файлах заголовков для предоставления функций, которые могут быть встроены (из-за отсутствия внешней связи) без выдачи предупреждений.
К сожалению, я не могу найти никаких доказательств этой логики. Даже из документации GCC я не смог сделать вывод, что inline
блокирует предупреждения о неиспользуемых функциях. Буду признателен, если кто-нибудь поделится ссылками на описание этого.
warning: unused function 'function' [clang-diagnostic-unused-function]
для static inline
функции при сборке clang-tidy
(v8.0.1), который используется в другой единице трансляции. Но определенно, это одно из лучших объяснений и поводов для объединения static
& inline
!
В языке C это static
означает, что определяемая вами функция или переменная может использоваться только в этом файле (то есть в модуле компиляции).
Итак, это static inline
означает встроенную функцию, которая может использоваться только в этом файле.
РЕДАКТИРОВАТЬ:
Единица компиляции должна быть единицей перевода
the compile unit
, что это что-то, что я написал по ошибке, такого не существует, фактическая терминологияtranslation unit
Одно отличие не на уровне языка, а на уровне популярной реализации: некоторые версии gcc static inline
по умолчанию удаляют функции, на которые нет ссылок, из вывода, но сохраняют простые static
функции, даже если на них нет ссылок. Я не уверен, к каким версиям это относится, но с практической точки зрения это означает, что всегда полезно использовать inline
для static
функций в заголовках.
inline
в определении? Вы также подразумеваете, что не используете его для extern
функций?
attribute((used))
и их использование, чтобы позволить asm ссылаться на static
функции и данные, на которые в противном случае не было бы ссылок .
static
относится к сфере применения. В языке C это означает, что функция / переменная может использоваться только в одной и той же единице перевода.