Как правильно встроить статические библиотеки
Я переписываю небольшую мою C-математическую библиотеку, которая в конечном итоге станет статической библиотекой для пользователя и хотела бы извлечь выгоду из встраивания для моего векторного математического интерфейса.
У меня есть следующее:
[mymath.h]
...
...
extern float clampf( float v, float min, float max );
...
...
[mymath.c]
inline float clampf( float v, float min, float max )
{
if( v < min ) v = min;
if( v > max ) v = max;
return v;
}
Так как моя библиотека будет статичной, и я только собираюсь предоставить .h
(и .lib
) пользователю, будет ли clampf
функция будет встроена в их программу при компиляции?
Я правильно делаю, но объявляя функцию extern
в .h
и встроенный в .c
?
2 ответа
У вас это почти правильно. У вас действительно есть это задом наперед; для встроенных функций вы должны поставить inline
определение в заголовочном файле и extern
декларация в файле C.
// mymath.h
inline float clampf( float v, float min, float max )
{
if( v < min ) v = min;
if( v > max ) v = max;
return v;
}
// mymath.c
#include "mymath.h"
extern float clampf( float v, float min, float max );
Вы должны поместить определение (полное тело) в файл заголовка, это позволит любому файлу, который включает файл заголовка, иметь возможность использовать встроенное определение, если компилятор решит это сделать.
Вы должны поставить extern
объявление (прототип) в исходном файле, чтобы сказать компилятору выдать внешнюю версию функции в библиотеке. Это обеспечивает одно место в вашей библиотеке для не встроенной версии, так что компилятор может выбирать между встраиванием функции или использованием общей версии.
Обратите внимание, что это может не работать с компилятором MSVC, который имеет очень слабую поддержку в целом для C (и практически не поддерживает C99). Для GCC вам необходимо включить поддержку C99 для старых версий. Современные компиляторы Си поддерживают этот синтаксис по умолчанию.
Альтернатива:
Вы можете изменить заголовок, чтобы иметь static inline
версия,
// mymath.h
static inline float clampf(float v, float min, float max)
{
...
}
Однако это не обеспечивает не встроенную версию функции, поэтому компилятор может быть вынужден создать копию этой функции для каждой единицы перевода.
Заметки:
Правила встраивания C99 не совсем интуитивно понятны. Статья " Встроенные функции в C" ( зеркало) описывает их подробно. В частности, перейдите к основанию и посмотрите "Стратегии использования встроенных функций". Я предпочитаю метод № 3, поскольку GCC уже некоторое время по умолчанию использует метод C99.
Технически, вам никогда не нужно ставить
extern
в объявлении функции (или определении), так какextern
по умолчанию. Я положил это там для акцента.
Вы должны определить свою функцию как static inline
в.h файле:
static inline float clampf( float v, float min, float max )
{
if( v < min ) v = min;
if( v > max ) v = max;
return v;
}
Функция должна отсутствовать в файле.c.
Компилятор может решить не включать функцию, а сделать ее правильным вызовом функции. Таким образом, каждый сгенерированный файл.o может содержать копию функции.