Существует ли стандартный способ, позволяющий потребителям библиотеки stati c определять функции, используемые в библиотеке (C) - PullRequest
0 голосов
/ 02 мая 2020

Вопрос

Существует ли "idiomati c" или стандартный способ (в C), позволяющий потребителям библиотеки stati c "вставлять" в нее пользовательский код в четко определенных точках, чтобы предоставить потребителю специфику поведения c?

Фон

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

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

Таким образом, проект структурирован как «многоцелевой проект», в котором мы имеем организацию, подобную следующей:

lib/
  somelib1/
  somelib2/

common/
  chip_drivers // from silicon vendor
  SOM_drivers  // HW drivers for stuff on the SOM
  reuseable_business_logic // don't want to copy-paste into each app

apps/
  app1/ 
    app1_layer1/
    app1_layer2/
    main.c

  app2/
    app2_layer1/
    app2_layer2/
    main.c

Я полагаю, что элементы в lib/ и common/ каталоги должны быть скомпилированы как stati c библиотеки и связаны с обоими образами приложений. Однако что, если что-то в common/reusable_business_logic должно зависеть от функции, "экспортируемой" приложением? Большая часть кода reusable_business_logic действительно переносима, однако в конечном итоге может потребоваться вызвать пользовательский app_send() функция, которая меняется в зависимости от того, связана ли она с app1 или app2 (определяется на уровне приложения).

Попытка решения

Я представляю себе способ сделать так, чтобы слой common/reusable_business_logic вызывал невыполненную функцию, которая может быть решена во время соединения. Итак, функции в общем слое определяют extern some_type app_send(some_type) как extern в файле общего заголовка и затем свободно используют его в коде. Между тем, в то время как app1 и app2, потребители общей бизнес-логики c, должны были бы определить свою собственную соответствующую реализацию этой функции для построения.

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

Ответы [ 2 ]

1 голос
/ 02 мая 2020

Я видел, как это делалось одним из двух способов:

Во-первых, как уже упоминалось в комментариях, обратные вызовы. Это довольно широко используется и прост в реализации. Простая передача указателей на функции в общий код во время инициализации может быть совершенно правильным способом для go, хотя он действительно вводит состояние, которое в противном случае не должно вызывать беспокойство.

Во-вторых, в значительной степени то, что вы уже пробовал - в проекте указаны c заголовки. По сути, общий код имеет только заголовок / набор заголовков, объявляющих прототипы для функций, которые должен реализовать целевой код c (обычно, отделенный от заголовков, используемых самим общим кодом) и этих заголовков. используются отдельными реализациями, каждая из которых определяет требуемые функции. В библиотеке будет отсутствовать определение целевых спецификаций c функций, но это ничего особо не изменит - пока существует определение для всех используемых функций ко времени, когда конечный исполняемый файл будет связан, существует действительно не должно быть никаких проблем. Это не является ни редким, ни особенно плохим решением проблемы, которую вы решаете; он довольно явно поддерживается инструментами и позволяет решить проблему без каких-либо накладных расходов - полученный двоичный код такой же, как если бы все повторно используемые компоненты были скопированы в каждый проект и использованы напрямую, без необходимости делать это.

Вариант второго варианта - использовать слабые символы (по крайней мере, объявленные как __attribute__((weak)) в G CC и потенциально объявленные по-разному в разных компиляторах) - это позволяет вам иметь реализации по умолчанию для целевой спецификации c , включенный в саму библиотеку - это на самом деле ничего не меняет, но может быть полезно, если большинство целей просто нуждается в реализации «по умолчанию», но для некоторых потребуется указать c различий - таким образом, вы можете избежать повторного использования. - написание значения по умолчанию для всех реализаций, которые его используют.

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

0 голосов
/ 02 мая 2020

В наших автомобильных ECU мы используем AUTOSAR с его абстракцией MCAL и абстракцией HW более высокого уровня и услугами на основе каналов и RTE с компонентами SW, а также его портами и интерфейсами.

Еще одна функция AUTOSAR - это возможное разделение между конфигурацией PRECOMPILE, LINKTIME и POSTBUILD.

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

Это позволяет также использовать физические каналы (проводные HW) и логические каналы отображаются на физические каналы и поведение логических каналов на основе их ChannelId. Кроме того, Frames / PDU абстрагируются PduIds и его настроенными выносками в каждой конфигурации.

На этапе загрузки / запуска у нас есть определенный механизм обнаружения, который может, например, использовать общую c «неизвестную» конфигурацию, который позволяет обнаруживать после частичного выключения и реконфигурации окончательную инициализацию и настройку запуска, например, переконфигурировать стек связи для левого / правого ЭБУ (включая маршрутизацию в одном или обоих ЭБУ между каналами, поворачивая канал, потому что это не подключен к другому ЭБУ), имея на обоих ЭБУ выход ШИМ, который используется в одном положении для управления зуммером, когда он управляет нагревателем или светодиодом на другом ЭБУ.

AUTOSAR CompilerAbstraction позволяет абстрагировать компилятор Отличий, например __attribute__ против #pragma или @far / @near, и не загрязнять код такими различными спецификаторами компилятора c, которые обрабатываются #ifdefs et c.

AUTOSAR MemoryMapping позволяет разместить CODE / CONST / CONFIG_DATA (конфигурация BSW) / VA R (данные) на отдельные секции памяти, например, чтобы разделить CODE из CONFIG_DATA на отдельно перепрограммируемые секции fla sh.

Для вашей бизнес-логики c, попробуйте выяснить реализацию библиотек алгоритмов, таких как Debounce, Контроллер P / PI / PID и т. Д. c, где конфигурация и состояние передаются вместе со значением.

Преимущество AUTOSAR заключается в том, что вам не нужно хранить все конфигурируемые части в ценном ОЗУ, например здесь так часто упоминается «передать функцию обратного вызова по указателю», потому что вы должны поддерживать эти обратные вызовы в оперативной памяти.

И вы можете создавать различные конфигурации в AUTOSAR, как правило, с помощью инструмента конфигурирования и генерации.

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

В вашем примере драйверы и business_logi c будут иметь конфигурации, которые генерируются фактически для каждого приложения отдельно в вашем app1 / app2, l Каналы рукописного ввода и приложения вместе. Конфиги затем загружаются вашими основными. c файлами во время инициализации.

apps/
    app1/ 
        app1_layer1/
        app1_layer2/
        config/      <-- driver/business logic config app1
        main.c

    app2/
        app2_layer1/
        app2_layer2/
        config/      <-- driver/business logic config app2
        main.c
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...