Как лучше всего создать библиотеку из существующих функций?

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

Взгляните на следующую функцию, существовавшую внутри программы:

char* Num_to_HEX_char_array(int32_t value)
{
  Clear_array(MyTempArray, MY_TEMP_ARRAY_LENGTH);
  ltoa(value, MyTempArray, HEX);
  return MyTempArray;
}

(Проигнорируем тот факт, что эта функция) Его нельзя сразу превратить в библиотеку, так как MyTempArray не существует. Это, в файле .cpp, мне придется вручную создать эти строки:

#define MY_TEMP_ARRAY_LENGTH 20
char MyTempArray[MY_TEMP_ARRAY_LENGTH];

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

Как лучше всего создать эту библиотеку?

*Одним из подходов, который я придумал, было динамическое создание этих массивов с помощью malloc(). И затем в основной программе вам нужно будет realloc() массивы с теми, которые вы хотите. Также используйте undef и пере#define. Недостаток этого подхода заключается в том, что вы должны ВСЕГДА использовать эти операторы, если хотите, чтобы ваша библиотека работала

*Другой подход заключается в размещении всего этого кода:

#define MY_TEMP_ARRAY_LENGTH 20
char MyTempArray[MY_TEMP_ARRAY_LENGTH];

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

Мой вопрос к этому подходу: как именно вы можете убедиться, что этот файл конфигурации читается всеми библиотеками?

Возможно, у вас много библиотек, например, обработка строк или обработка датчиков... Каждая из этих библиотек, созданных пользователями, должна #include просмотреть этот заголовочный файл конфигурации, чтобы убедиться, что определения и массивы имеют правильное имя и размер. Как сделать так, чтобы его видели все ваши пользовательские библиотеки? Где оптимально разместить этот файл?

Вообще, как лучше всего решить эту проблему?

, 👍-1

Обсуждение

что вы имеете в виду, когда говорите «лучший»?, @jsotola


3 ответа


2

Я бы написал такую функцию, ожидающую, что вызывающая функция выделит массив и передаст его и его размер в качестве аргументов. Таким образом, выделение и освобождение памяти остается на усмотрение каждого пользователя библиотеки, который может захотеть/нужно (по другим причинам) использовать статический массив, динамическую память или автоматический массив и позволяет им освобождать ее (или нет), когда их приложению это больше не нужно. Кодирование этих данных в вашей библиотеке ограничит ее использование.

,

2

Прежде всего, я должен сказать, что у меня есть проблема с приведенным вами примером. Функция Num_to_HEX_char_array() должна использовать массив с максимальный размер, который может когда-либо понадобиться ltoa(). Не больше, не меньше. Здесь нет указать на то, чтобы позволить пользователю библиотеки выбрать этот размер. Вот как я будет реализовывать эту функцию:

char *Num_to_HEX_char_array(int32_t value)
{
    static char buffer[2 * sizeof(long) + 1];
    return ltoa(value, buffer, HEX);
}

При этом я согласен с тем, что в вашей библиотеке есть некоторые статические буферы, для которых имеет смысл позволить пользователю выбирать размер. Вероятно, вы могли бы найти лучший пример, чтобы поместить его в хотя вопрос.

В этом случае я бы посоветовал вам сначала рассмотреть предложенный подход JRobert, и пусть пользователь предоставляет эти буферы. Использование статических буферов в библиотеке может упростить использование API в наиболее распространенных случаях. В стандартной библиотеке C есть много функций, которые делают это, например: например, ctime(). Однако за это приходится платить:

  • пользователь должен быть хорошо осведомлен о том, что обращения к библиотеке могут данные, возвращенные предыдущими вызовами

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

Вот почему у вас есть такие функции, как ctime_r(): предоставить альтернатива, которая позволяет пользователю управлять буфером и не страдает от предыдущих недостатков.

Если вы все еще считаете, что вам нужны статические буферы в вашей библиотеке, тогда вы должны сначала подумать, можно ли исправить размер, например в примере Num_to_HEX_char_array(). Если это невозможно, то лучшее, что я могу придумать, это использовать шаблоны C++. Например:

template<size_t size> class CircularBuffer {
    int buffer[size];
    // ...
};

который будет создан следующим образом:

// Пусть `queue' будет циклическим буфером на 42 слота.
CircularBuffer<42> queue;

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

,

1

Компиляторы командной строки и большинство IDE для C и C++ позволяют задавать определения проекта как параметры -D в настройках проекта. В Arduino IDE это еще не реализовано, потому что в нем нет файла конфигурации проекта.

С помощью Arduino IDE вы можете добавлять определения для платформы или для определений платы с помощью build.extra_flags в файле platform.local.txt или boards.local.txt. Пример для boards.local.txt для Arduino Mega:

mega.build.extra_flags=-DUIP_CONF_UDP_CONNS=20 -DUIP_CONF_MAX_LISTENPORTS=30

platform.local.txt и boards.local.txt должны находиться в папке пакета boards, а не platform.txt и boards.txt.

,