Полезно ли когда-либо «inline» без «static» или «extern» в C99?

Когда я пытаюсь собрать этот код

inline void f() {}

int main()
{
    f();
}

с помощью командной строки

gcc -std=c99 -o a a.c

, я получаю ошибку компоновщика (неопределенная ссылка на f ). Ошибка исчезает, если я использую static inline или extern inline вместо просто inline , или если я компилирую с -O (поэтому функция фактически встроена).

Такое поведение, по-видимому, определено в параграфе 6.7.4 (6) стандарта C99:

Если все объявления области видимости файла для функции в модуле перевода включают inline спецификатор функции без extern , тогда определение в этой единице перевода является встроенным определением. Встроенное определение не предоставляет внешнего определения функции и не запрещает внешнее определение в другой единице перевода. Встроенное определение предоставляет альтернативу внешнему определению, которое переводчик может использовать для реализации любого вызова функции в той же единице перевода. Не указано, использует ли вызов функции встроенное определение или внешнее определение.

Если я все это правильно понимаю, модуль компиляции с функцией, определенной встроенной , как в приведенном выше примере, компилируется только согласованно если существует также внешняя функция с тем же именем, и я никогда не знаю, вызывается ли моя собственная функция или внешняя функция.

Разве такое поведение не является совершенно глупым? Полезно ли когда-нибудь определять функцию inline без static или extern в C99? Я что-то упустил?

Сводка ответов

Конечно, я чего-то упустил, и поведение не дурацкое. :)

Как Nemo объясняет , идея состоит в том, чтобы поместить определение функции

inline void f() {}

в файл заголовка и только объявление

extern inline void f();

в файле соответствующий файл .c. Только объявление extern запускает генерацию видимого извне двоичного кода. И действительно, inline в файле .c не используется - он полезен только в заголовках.

Как поясняет обоснование комитета C99, процитированное в ответе Джонатана , inline - это оптимизация компилятора, которая требует, чтобы определение функции было видимым на месте вызова. Это может быть достигнуто только путем помещения определения в заголовок, и, конечно же, определение в заголовке не должно генерировать код каждый раз, когда его видит компилятор. Но поскольку компилятор не обязан фактически встраивать функцию, где-то должно существовать внешнее определение.

91
задан Community 23 May 2017 в 11:54
поделиться