Относительно:
static void static_func(void);
void static_func(void) { }
Для первой строки C 2018 6.2.2 3:
Если объявление идентификатора области файла для объекта или функции содержит спецификатор класса хранения static
, идентификатор имеет внутреннюю связь.
Для второй строки 6.2.2 5 говорит:
Если объявление идентификатора для функции не имеет спецификатора класса хранения, его связь определяется точно так, как если бы оно было объявлено с помощью спецификатора класса хранения extern
.…
поэтому мы ссылаемся на параграф о том, когда extern
указано, 6.2.2 4 (выделение добавлено):
Для идентификатора, объявленного с помощью спецификатора класса хранения extern
в области видимости, в которой видно предыдущее объявление этого идентификатора, , если в предыдущем объявлении указана внутренняя или внешняя связь, связь идентификатор в более позднем объявлении такой же, как связь, указанная в предыдущем объявлении.…
Таким образом, поскольку предыдущее объявление является видимым, void static_funct(void)
эквивалентно static void static_funct(void)
.
(Обратите внимание, что 6.2.2 5 отличается для объектов; после части, указанной выше, он продолжает: «Если объявление идентификатора для объекта имеет область файла и не имеет спецификатора класса хранения, его связь является внешней. Таким образом, static int x; int x;
создает конфликт для объекта x
, тогда как static int f(void); int f(void);
не создает конфликт для функции f
.)
Относительно:
static inline void static_inline_func(void);
void static_inline_func(void) { }
inline
- это спецификатор функции, а не спецификатор класса хранения, и 6.7.4 6 говорит нам:
Функция, объявленная со спецификатором функции inline
, является встроенной функцией .…
Как мы видели выше, void static_inline_func(void) { }
все еще имеет внутреннюю связь из-за предварительного объявления. 6.7.4 7 довольно слабо относится к требованиям к встроенным функциям с внутренней связью:
Любая функция с внутренней связью может быть встроенной функцией.…
Если бы функция не была объявлена с static
, есть дополнительные ограничения в 6.7.4 7:
Для функции с внешним связыванием применяются следующие ограничения: Если функция объявлена со спецификатором функции inline
, то она также должна быть определена в той же единице перевода. Если все объявления области файла для функции в модуле перевода включают в себя спецификатор функции inline
без extern
, то определение в этом модуле перевода является встроенным определением. Встроенное определение не предоставляет внешнего определения для функции и не запрещает внешнее определение в другой единице перевода. Встроенное определение предоставляет альтернативу внешнему определению, которое переводчик может использовать для реализации любого вызова функции в той же единице перевода.…
(Непонятно, где заканчивается текст, охватываемый «применяются следующие ограничения».)
Таким образом, может существовать как встроенное определение функции, так и внешнее определение (в другой единице перевода). В любом случае, по-видимому, нет никаких запретов на объявление функции как с inline
, так и без него; это имеет всего лишь последствия, в частности, объявление внешней функции как с inline
, так и без него означает, что определение в этой единице перевода не является встроенным определением.