Как различить массив в RAM и в PROGMEM?
- Войдите на сайт для отправки комментариев
Чт, 01/07/2021 - 08:55
Собственно, нужно написать функцию (семейство одноименных функций), которые будут адекватно работать как с массивами в оперативной памяти, так и во флеш-памяти.
Для символьных массивов можно использовать типы данных char и __FlashStringHelper соответственно. А как быть с массивами других типов?
void myFunc(char* ch); // работает с массивами в оперативной памяти void myFunc(__FlashStringHelper* ch); // работает с массивами в flash
Создать свой фейковый пустой тип данных по подобию __FlashStringHelper и аргумент приводить к нему?
Можно воспользоваться тем, что массив в PROGMEM всегда const и одной хитростью процедуры поиска нужной функции при перегрузке, а именно: если для обычных переменных модификаторы const и volatile не создают разницы (функции считаются одинаковыми), то для указателей и ссылок - ещё как! А массивы, как раз и есть указатели.
Вот пример Здесь функция doInt перегружена а вся разница как раз в const.
Одно ограничение - массивы не в PROGMEM не должны быть const, чтобы не принять их за PROGMEM'ые
К великому сожалению авторы GCC, не скажу про другие компиляторы, не дали программисту способа использовать в шаблонах или перегрузках известную компилятору информацию об АТРИБУТАХ переменной. :((
Остается "расово-верный" путь, истиного ООП. :))
Нужно создать класс для массивов, который содержит в себе информацию о местоположении (РАМ/РОМ) своих данных. При некой ловкости, как недавно показал ДетСимен, можно даже инициализировать такой массив "как настоящий" ;)) Хотя я бы, все таки выбрал путь конструктора.
Тогда функции обработки будут всегда одинаковые - для этого класса. Их можно вообще методами сделать. И преобразовалки типа из обычного массива, причем можно как с копированием, так и с переносом только указателя.
Путь, предложенный Женей оставляет огромный простор для "стрельбы себе в ногу". Хотя хозяин - барин! ;))
Сделать тот же flashstringhelper для других типов.
для "стрельбы себе в ногу".
Енто мы могём! Собсна, это значимая часть профессионального юмора.
Создать свой фейковый пустой тип данных по подобию __FlashStringHelper и аргумент приводить к нему?
Да, это первое, о чем я подумал. Но подумать - мало, нужно еще знать, как (я никогда не скрывал, что для меня С/C++ не являются родными языками).
Единственное, что я нашел в папке Arduino:
только, сдается мне, здесь определяется только макрос F(), а определения самого класса мне найти не удалось.
Т.е. образца, чтобы сделать "по подобию" у меня нет, а собственных знаний чтобы сделать без образца - не хватает.
Не получилось даже описать экземпляр класса:
ни первая, ни вторая строка не компилируется (ошибка: incomplete type).
Да, сделайте как в моём примере, делов -то.
Тем более, что если делать свой хелпер - это будет полноценный класс, примерно как граф описывал. Халтуркой типа "тайпдефом тот же инт переобозвать" не отделаешься, т.к. тайпдеф не создаёт нового класса, а только синоним существующего. Так что гемора там будет достаточно.
если для обычных переменных модификаторы const и volatile не создают разницы (функции считаются одинаковыми), то для указателей и ссылок - ещё как! А массивы, как раз и есть указатели.
Да, с формулировано четко, но мне удалось подобрать примеры, где преобразование происходит по каким-то другим правилам. В частности неконстантный int8_t почему-то распознается как PROGMEM.
результат работы:
Примечание: во всех результатах "правильным" числом является 49. Если в выводе что-то другое, имеет место ошибка распознавания.
Остается "расово-верный" путь, истиного ООП. :))
Нужно создать класс для массивов...
Да, иногда я для себя так и делаю. Но осложнение в том, что я делаю библиотечку, которую собираюсь выложить в общий доступ. А значит, при использовании другими людьми там неизбежно будет "зоопарк". Вот хотелось бы сделать внутреннюю часть библиотечки так, что бы этот "зоопарк" с пользовательской стороны не создавал проблем.
Вот хотелось бы сделать внутреннюю часть библиотечки так, что бы этот "зоопарк" с пользовательской стороны не создавал проблем.
Не получится. Делай буквальные вызовы.
Вы что-то напутали. Я взял Ваш пример, выбросил из него всё, кроме uint8_t и всё отлично работает
Код:
Результат:
Что там с полным примером я не стал разбираться, сами разберётесь.
Единственное, что я нашел в папке Arduino:
только, сдается мне, здесь определяется только макрос F(), а определения самого класса мне найти не удалось.
А оно так и работает - пустой фейковый класс чисто для приведения типа к нему, чтобы была вызвана соответствующая overload-функция, в которой уже применяются соответствующие для PROGMEM методы доступа.
Типа такого:
Я взял Ваш пример, выбросил из него всё, кроме uint8_t и всё отлично работает
Вот именно!
Когда что-то добавляешь или выбрасываешь из функций, реакция остальных изменяется существенным образом.
Крайний случай - единственный массив и единственная функция - работают всегда!
Что-то тут не то. Так не бывает :-(
Как это не бывает?
Наоборот - не может быть иначе: если мы добавляем функцию, то она "отбирает" часть вызовов у других функций.
Ну, разве что :-)
"Гоп-функция" - отжимает вызовы! ;)))))
Попкорн? ;)))