Как спроектировать универсальный обратно совместимый API для интерфейса библиотеки встроенных приложений в C? - PullRequest
0 голосов
/ 01 октября 2019

Мне поручено помочь в разработке динамической библиотеки (предоставляемой с интерфейсом C), предназначенной для использования в программном обеспечении для встраивания на различных платформах встраивания (Android, Windows, Linux).

Основными требованиями являются скорость и развязка. Для развязывающей части: одно из наших требований заключается в том, чтобы иметь возможность облегчить интеграцию и обеспечить обратную совместимость и устойчивость.

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

Итак, я пришел с несколькими предложениями, но, поскольку каждое из них не кажется хорошим, я ищу совет о лучших или стандартных способах достижения развязки и обратной совместимости, чемэто 3 способа, которые я нашел:

  • Первый вариант, о котором я мог бы подумать, - это создать общий интерфейсный вызов для моих открытых точек входа, например, с хэш-картой ключей / значенийдля параметров моих функций, поэтому в псевдокоде это дает что-то вроде:

    myLib.Initialize (Key_Value_Option_Array_Here);

  • Другой вариант - предоставить универсальную функцию для предоставлениявсе параметры библиотеки:

    myLib.SetOption (Key_Of_Option, Value_OfOption);myLib.SetCallBack (Key_Of_Callbak, FunctionPointer);

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

    Есть ли более эффективный или стандартный способ, о котором вы могли бы подумать?

1 Ответ

1 голос
/ 01 октября 2019

У вас может быть структура для необязательных аргументов:

typedef struct {
    uint8_t optArg1;
    float optArg2;
} MyLib_InitOptArgs_T;


void MyLib_Init(int16_t arg1, uint32_t arg2, MyLib_InitOptArgs_T const * optionalArgs);

Тогда вы можете использовать составные литералы при вызове функции:

MyLib_Init(1, 2, &(MyLib_InitOptArgs_T){ .optArg2=1.2f });

Все неуказанные значения будут иметь нулевое значениезначение (0, NULL, NaN) и будет считаться неиспользованным. Аналогично, при передаче NULL для указателя структуры все необязательные аргументы будут считаться неиспользуемыми.

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


Другой вариант - просто иметь несколько меньших функций инициализации для инициализации различных подсистем. Это может быть объединено с системой необязательных аргументов выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...