Статическая библиотека строит и включает в себя - PullRequest
2 голосов
/ 24 марта 2019

Я создаю статическую встроенную C-библиотеку, в которой есть файл заголовка API, в котором перечислены все доступные функции.Я не уверен в некоторых вещах, которые я хотел бы уточнить в первую очередь, прежде чем приступить к его реализации.

Прежде всего, поскольку это C-библиотека для встроенных систем, в которой есть аппаратный FPU, яя не уверен, что мне следует включить для вычисления математических функций, таких как sinf () и т. д. Обычно я использую аппаратные включения, но это не доступно в этой статической C-библиотеке, поскольку она может работать на некоторых STM32 или даже на некоторых AVR и т. д.Как я могу решить эту проблему?

Далее скажем, у меня есть файлы foo.c и foo.h, которые предоставляют некоторые скрытые функции в библиотеке, а затем есть api.h, который можно увидетьпользователем и api.c, который также скрыт.В foo.h теперь определены некоторые структуры, которые я хотел бы вернуть в обратном вызове для пользователя.Поскольку эти структуры скрыты, я не уверен, как мне следует обрабатывать эти обратные вызовы.Должен ли я реализовать обработчик в api.c, который отображает структуры из обратного вызова из foo.c и передает их в обратный вызов пользователя, где структуры переопределяются (с другим именем) в api.h или есть решения с меньшими издержками?

Когда я определю необходимые структуры для foo.h в api.h, мне нужно будет включить api.h в foo.h, но также и foo.h в api.h, это нехорошая идея, я думаю.

1 Ответ

2 голосов
/ 24 марта 2019

Для первой части вопроса математические операции, такие как sinf, должны обрабатываться стандартной библиотекой C (вам следует проверить конкретную версию на предмет поддержки вашей архитектуры).Затем вы можете использовать заголовок math.h и его функции, компилятор должен затем использовать FPU для выполнения вычислений с плавающей запятой.


Для второй части - обычный способ показать пользователю скрытыйструктура с декларацией foward , но пользователю придется взаимодействовать со структурой с помощью указателей и функций доступа.

В качестве примера, скажем, у нас есть четыре файла:

  • api.h: открытый заголовок
  • api.c: исходный код для функций из открытого заголовка
  • foo.h: внутренний заголовок библиотеки (не будет доставлен конечному пользователю)
  • foo.c: исходный код для внутренних функций

api.h - единственный интересный файл из них (без изменений).

// file: api.h
#ifndef API_H
#define API_H

struct foo; // forward declaration of the foo structure

typedef void (*callback_t)(struct foo*); // typedef for a callback taking a
                                         // struct foo argument

void set_callback(callback_t fn);
#endif

Теперь у нас есть тип для обратного вызова и тип структуры, заданной для обратного вызова, но пользователь не может взаимодействовать с самой структурой, поскольку компилятор только знает, что она существует, но не знает ее содержимого (и размера хранилища)..

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

#include "api.h"

void user_callback(struct foo* arg) {
    // user code here
}

Функции доступа обычно определяются следующим образом:

// in the file api.h or another header that the user has access to

int foo_get_value1(struct foo* arg);
void foo_set_value1(struct foo* arg, int new_value);

и эти функции будут реализованы в foo.c

struct foo {
    int value1;
    int value2;
};

int foo_get_value1(struct foo* arg) {
    return arg->value1;
}

void foo_set_value1(struct foo* arg, int new_value) {
    arg->value1 = new_value;
}

Этот подход имеет дополнительное преимущество, заключающееся в том, что ваши foo_set функции могут выполнять проверки достоверности, чтобы убедиться, что у вас есть соответствующие значения вструктура.

Обратите внимание: Я не добавил никаких проверок в свои функции доступа, чтобы избежать загромождения кода, но при передаче указателя на функцию всегда следует проверять его на * 1047.*

...