А можно я тоже прилеплюсь со странным абстрактным желанием укротить switch, раз уж тут достопочтимые будущие лорды собрались?
Клапауция давно не видно, а без него кто ж запретит?
@Adinah уже настоящий. Я его теперича называю “Ваша Светлость”.
Может, конечно, я уже спрашивал - терзаюсь давно, но всё больше припадками.
Стало быть, есть у меня древний исходник в парадигме функционального программирования на цэ, который имеет свич-селектор функций, в которых никакой особой системности не усматривается. Наборы аргументов могут быть разные, предварительные проверки перед их вызовом тоже могут быть, могут не быть… Вобщем, анархия - мать порядка. Так происходит, потому что селектор выбирает какой датчик опросить, а датчики вообще все разные и… ну вы сами поняли. Параметры приходят извне (из сети).
Т.к. этот свич адский, то он скоро в трёхтомник перестанет влезать. Давно хочу его как-то поделить на части, но не могу понять как усидеть на двух стульях - и чтобы коротенькие кусочки (подфункции?) получились и бинарник не вырос (упихиваюсь в 328-й мк с сетью, экономлю на всём).
Пример (с абстрактными функциями):
switch (cmd) {
...
#ifdef(DHT_ENABLE)
case DHT_TEMPERATURE: {
result = getDHT(inPin, METRIC_TEMP);
break;
}
#endif
#ifdef(BMP_ENABLE)
case BMP_TEMPERATURE: {
result = getBMP(sdaPin, sclPin, i2cAddress, METRIC_TEMP);
break;
}
#endif
#ifdef(MHZ-19_ENABLE)
case MHZ-19_CO2: {
result = 400;
if (elapsedTime > 2000) { result = getMHZ19(rxPin, txPin, METRIC_CO2); }
break;
}
#endif
...
}
И такая колбаса на полтора километра. Добавлять новые сенсоры, конечно, просто, но вот баги искать - так себе удовольствие.
Вобщем, женимапасисжур, помогите бывшему депутату… Если есть вообще такая возможность оптимизировать без ожирения прошивки. Уже даже хотел тупо в инклюд-файлы распихать ветки…
Два вопроса:
- константы (
DHT_TEMPERATURE
,MHZ_19_CO2
и т.п.) сами определяете или “Бог послал”? - в любом случае результатом является изменение
result
или возможны варианты?
Каждая функция опроса датчика переписывается до приема одного аргумента - структуры с обьединением всего множества параметров.
Свич меняется на выбор указателя на функцию по аргументу (параметру нынешнего свича). Массив указателей на функции создается при инициализации. Каждая функция опроса датчика из структуры в параметре выбирает только необходимые ей поля.
Хотя, в парадигме однопоточного программирования параметр функций можно убрать полагаясь на наличие этой структуры в глобальной области. Точно так же и результат возвращать в глобальную переменную.
- Всё своё, с огорода.
- Немного сложнее: result - это return code, в сущности, а указатель на буфер для результата работы функции передаётся в аргументах. Это может и int32* быть и char*.
я бы переписал этот свитч в набор шаблонов по INT значениям cmd, где для каждого значения DHT_TEMPERATURE
, MHZ_19_CO2
прописал бы отдельную специализацию.
Премущество будет в том, что в готовый код будут автоматически попадать только те функции, что в нем задействованы, условная компиляци я станет не нужна
Хотя нет… еркнду написал.Нужный набор функций ведь становится известен только в ран-тайм?
Да мне всё равно, что это. Вопрос-то был … оно всегда назначается или возможны варианты?
Из функций всегда возвращается код возврата, как я помню. Но если и есть три-четыре void, то их обернуть можно.
Нет, пользователь выбирает в конфиге (.h-файл) какие сенсоры инклюдить. Иначе только в мегу пихать.
С темплейтами не совсем понял. Темплейтов будет по количеству кейсов и их вызовы все подряд писать? А как тогда выбор будет осуществлён?
Это удар по памяти, как я себе представляю. Или в прогмем напихивать как-то…
Не стало бы сложнее прежнего ))
Вобщем, если хочется совсем точно посмотреть, то с 478 строки: zabbuino/zabbuino.ino at master · zbx-sadman/zabbuino · GitHub
Читать досконально не обязательно (я и сам боюсь), просто полистать.
Да. Но нужно чтобы у всех функций совпадали число и тип аргументов.
По идее нет, вызов нужен один, но здесь это не сработает, т.к. ключевой параметр – не константа.
Шаблоны имеют смысл, когда значения ключевых параметров (тех, по которым определяется что именно вызывать) известны на этапе компиляции. Тогда как раз всё красиво – пишется один вызов, а компилятор подставляет нужный вариант из 100500 возможных.
Если бы Вы сделали так – архив, а в нём:
- Сама программа со всеми причиндалами в папке с правильным названием;
- Папка
libs
, а в ней подпапками все библиотеки (чтобы я просто скопировал Вашуlibs
в свою libraries и всё после этого успешно скомпилировалось хоть для Меги)
То я бы попробовал повозиться. Есть идеи, но там лучше по месту смотреть.
Либо оставляте свич, но он становится простейшим, не сильно отличаясь от кода инициализации массива, т.к. аргументы исчезают. Можно даже задефайнить. Либо хитрить с прогмем, но у меня нет опыта запихивать туда адреса функций.
С оборачиванием в дефайн однотипных кейсов в свичах я давно работаю на больших компьютерах. Поскольку это лишь синтаксический сахар, ошибиться и затруднить отладку он не может.
#define SENS(ID, FUNC) case ID: result=FUNC(); break;
switch (param) {
SENS(SENSOR_1, getSensData1);
SENS(SENSOR_2, doReqSens2);
}
С условной компиляцией будет не так красиво, дефайн в дефайне не делается. Я бы глушил тела функций, ибо сам свитч кода занимает мало и живет в области программы не отьедая память переменных.
Поэтому я и был в некотором недоумении - как мне свич, селектирующий в рантайме, менять на шаблоны.
Вам прямо весь этот муравейник нужен или продуктивней будет предоставить что-то имитирующее, из десятка кейсов, к примеру?
Да, я бы этот дефайновый лишай тоже не разводил, если бы за каждый байт не бился. А так, выходит, что уже на этапе переосмысления начинаю в минус уходить.
Прямо так за каждый байт программного кода битва? Если так тесно, меняйте контроллер на тянущий задачу. Или компонуйте обработку датчиков отдельно, а логику на втором контроллере. Вопрос оптимальности алгоритмов не поднимаю, ибо там можно в разы ужаться бывает.
Интересен был бы живой пример. Может, при этом, и с оверхедом по свичу может будет смириться.