Во встроенном C вполне естественно иметь некоторый фиксированный / универсальный алгоритм, но более одной возможной реализации. Это происходит из-за нескольких презентаций продукта, иногда опций, в других случаях это просто часть стратегий стратегии продукта, таких как опциональное ОЗУ, другой MCU с IP-набором, повышенная частота и т. Д.
В большинстве моих проектов я имею дело с этим, отделяя основные компоненты, алгоритм и архитектуру логики от реальных функций, которые реализуют внешнюю оценку состояния, хранение времени, память и т. Д.
Естественно, я использую механизм указателей на функции C, и я использую набор значимых имен для этих указателей. Е.Г.
unsigned char (*ucEvalTemperature)(int *);
Тот хранит температуру в целых числах, а возвращаемое значение в порядке.
Теперь представьте, что для конкретной конфигурации продукта у меня есть
unsigned char ucReadI2C_TMP75(int *);
функция, которая считывает температуру на шине I2C с устройства TMP75 и
unsigned char ucReadCh2_ADC(unsigned char *);
функция, которая считывает падение напряжения на диоде, считываемое АЦП, что позволяет оценивать температуру при очень широких движениях.
Это та же базовая функциональность, но на разных продуктах с набором опций.
В некоторых конфигах у меня будет настройка ucEvalTempera на ucReadI2C_TMP75, а в других - ucReadCh2_ADC. В этом легком случае, чтобы избежать проблем, я должен изменить тип аргумента на int, потому что указатель всегда имеет одинаковый размер, но сигнатура функции не совпадает, и компилятор будет жаловаться. Хорошо ... это не убийца.
Проблема становится очевидной для функций, которым может потребоваться другой набор аргументов. Подписи никогда не будут правильными, и компилятор не сможет разрешить мои Fpointers.
Итак, у меня есть три способа:
- использовать глобальный стек аргументов, и все функции имеют тип unsigned char Func (void);
- использовать вспомогательную функцию для каждой реализации, которая позволяет мне включить правильное назначение для make / call;
- использовать вызовы сборки JMP / LCALL (что, конечно, ужасно), что может вызвать серьезные проблемы в стеке вызовов.
Ни элегантно, ни составно ... каков ваш подход / совет?