ПрограммированиеC/C++ инженер

Расскажите о различиях между функциями, объявленными как inline, и обычными функциями в C. Каковы ограничения, как правильно объявлять inline-функции при работе с несколькими исходными файлами, какие ошибки часто совершают разработчики?

Проходите собеседования с ИИ помощником Hintsage

Ответ

inline — подсказка компилятору заменить вызов функции её телом (вставкой кода). Это может ускорить выполнение (нет накладных расходов на вызов), но приводит к увеличению размера бинарника.

Синтаксис:

inline int square(int x) { return x * x; }

Компилятор вправе проигнорировать inline. Для одновременной видимости и реализации функции в разных файлах используют:

// header.h inline int min(int a, int b) { return a < b ? a : b; }

Всё тело функции должно быть доступно в каждом файле, где вызывается inline-функция, т.е. обычный способ — определять функцию в заголовочном файле.

Если объявить и определить inline-функцию только в одном .c-файле, то другие модули не смогут её использовать, возникнут ошибки компоновки (undefined reference).

Вопрос с подвохом

В чём отличие между такими объявлениями в заголовочном файле?

inline int foo(int x) { return x + 1; } static inline int bar(int x) { return x + 1; }

Ответ:

  • inline int foo(...) приводит к тому, что функция может иметь множество слабых определений (one definition rule). Если из нескольких .c-файлов включён один и тот же заголовок, компоновщик может выдать ошибку множественного определения.
  • static inline делает функцию внутренней для каждого модуля: каждая точка подключения получает свою копию, проблем на этапе линковки не будет. Это наиболее безопасно для inline-функций в заголовках.

Примеры реальных ошибок из-за незнания тонкостей темы


История

В библиотеке математических функций определяли множество inline-помощников в .c-файле. При попытке использовать их из других модулей возникали ошибки линковки, потому что определения были видны только в одном объектном файле.


История

После переноса inline-функций из .c-файла в заголовочный проект стал падать на этапе линковки: компоновщик жаловался на множественные определения одной и той же функции. Исправили заменой на static inline в заголовочных файлах.


История

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