Как правильно встроить статические библиотеки

Я переписываю небольшую математическую библиотеку 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 и inline в .c?

Ответы

Ответ 1

У вас это почти правильно. Вы действительно имеете это назад; для встроенных функций вы должны поместить определение 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 для старых версий. Современные компиляторы C поддерживают этот синтаксис по умолчанию.

Альтернатива:

Вы можете изменить заголовок, чтобы иметь версию static inline,

// mymath.h
static inline float clampf(float v, float min, float max)
{
    ...
}

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

Примечания:

  • Правила встраивания C99 не совсем интуитивно понятны. В статье "Встроенные функции в C" (mirror) подробно описывается. В частности, пропустите снизу и посмотрите "Стратегии использования встроенных функций". Я предпочитаю метод # 3, так как GCC уже некоторое время отказывается от метода C99.

  • Технически вам не нужно помещать extern в объявление функции (или определение), так как extern является значением по умолчанию. Я положил его туда для акцента.

Ответ 2

Вы должны определить свою функцию как 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 может содержать копию функции.