Вопрос к знатокам, отлитым в бронзе
- Войдите на сайт для отправки комментариев
Ср, 08/11/2017 - 06:42
Кто мне скажет ПОЧЕМУ лыжы не едуть?
template <typename T> Print &operator << (Print &s, T n) { s.print(n); return s; } const char dow00[] PROGMEM = "Monday"; const char dow01[] PROGMEM = "Tuesday"; const char dow02[] PROGMEM = "Wednesday"; const char dow03[] PROGMEM = "Thursday"; const char dow04[] PROGMEM = "Friday"; const char dow05[] PROGMEM = "Saturday"; const char dow06[] PROGMEM = "SunDay"; const char *const DoW_Array[] PROGMEM = { dow00,dow01,dow02,dow03,dow04,dow05,dow06 }; volatile byte idx = 0; using PFlashString = __FlashStringHelper *; PFlashString str; void setup() { Serial.begin(115200); Serial << F("Program started.\n"); str = PFlashString(dow02); Serial << idx << ". " << str << '\n'; idx++; str = PFlashString(DoW_Array[2]); Serial << idx << ". " << str << '\n'; idx++; str = PFlashString(DoW_Array[idx]); Serial << idx << ". " << str << '\n'; } void loop() { /* add main program code here */ }
Я безусловно идиот, и многого по С++ не знаю, но это выше моего понимания. ПАМАГИТИ!!!
Что-то с памятью её стало, стринги на ардуине не велкам. Есть макрос для измерения доступной памяти, поищите.
А не отлитым можно отвечать?
И кстати, дед, то что память не при делах, а просто ты запутался в квалификаторах - это понятно. Но, не веди себя как новичок - объясни чего ты хотел. Конкретный вопрос - чего ты хотел от массив DoW_Array? Он сам должен сидеть в оперативной памаяти или в програмной?
str = PFlashString(DoW_Array[2]); печатается правильно
str = PFlashString(DoW_Array[idx]); печатается неправильно, хотя idx == 2
пошто?
Наерно, это только Дракула сможет рассказать, пока трезв, или ЕвгенийП, если снизойдут.
Мля, я тоже могу, если ты мне ответишь на мой вопрос.
Сами строки у тебя живут в progmem, а массив указателей DoW_Array - где? Вернее, где ты хочешь, чтоб он жил?
Это относится к делу? Тогда хочу, чтоб в PROGMEM. Смысла нет держать массив константных указателей в оперативке
Кароче, у тебя два варианта.
1. или ты убираешь слово PROGMEM из строки 13 (попробуй)
2. или читаешь содержимое этого массива из progmem как положено, т.е. в строке 32 вместо DoW_Array[2] пишешь pgm_read_ptr_near(DoW_Array+2), а в строке 37 вместо DoW_Array[idx] пишешь pgm_read_ptr_near(DoW_Array+idx) (пробуй и это)
В любом из этих двух случаев у тебя всё будет работать правильно.
На вопрос: "относится к делу?" ответ уже понятен? Просто сравни два описанных выше варианта.
а я не спрашивал, что надо делать. Я спрашивал ПОЧЕМУ работает по разному при индексе массива == константа и при взятии его из переменной, хотя на мой взгляд, разницы быть не должно.
Потому, что в стоке 32 - константа и компилятор просто подставил готовое значение не вычисляя элемент массива по индексу - тупо сам вычислил и в исполняемом коде у тебя уже сидит готовая "среда".
А в строке 37 он вставил код для честного вычисления "к адресу начала массива прибавить содержимое idx и из получившегося адреса взять содержимое", а посколько это содержимое на самом деле сидит в прогмеме, вот он у тебя и сломался.
Я же во втором примере явно написал то же самое (к адресу прибавил содержимое idx) только при этом указал, что содержимое надо из прогмема брать, вот он нормально и сработал.
Мда. Говорила мне мама, не лезь в С++ со своим скудоумием.
Паду пить.
Это называется "неявное преобразование типов в С++" ?
DetSimen - когда я делал точно такую коллекцию строк в своем скрипте - я счастливо избежал этой ловушки, поместив массив указателей в оперативку. Указатели занимают мало, поэтому совершенно незачем класть их во флеш, зато работать с ними в оперативке много удобнее.
Всё равно нихрена не понимаю
где я баран?
где я баран?
ну вроде Ворота все понятно обьяснил в сообщении №9. В первых двух случаях адрес элемента известен на момент компиляции, в третьем - вычисляется в процессе выполнения. Вот и разница.
А смотрищь как баран на Ворота :)
ви таки не поверите, но вот так тоже не работает
Хотя тут то уже ничего не подставляется явно. Функция как inline не описана.
вопщем, я думаю, дожность помошника кочегара деревенской котельни при курятнике - потолок моей карьеры.
Вопрос снят, всем спасибо.
Пойду пить, а потом котельни обзванивать в области.
лучше обьясни мне другое - зачем в этой строке два раза const
const char *const DoW_Array[] PROGMEM = { dow00,dow01,dow02,dow03,dow04,dow05,dow06 };
Вот смотри - char* array[] - это массив указателей на данные типа char
const char* array[] - это массив, где эти указатели являются константами
А второй const - указание на то, что и данные по указателям - константы? - а зачем это обьявлять, ведь указателям все равно, на что указывать - на переменные или константы. А сами строки ты и так обьявил контантами и компилятор это учитывает.
По-моему, второй конст из определения массива можно безболезненно выкинуть. Или ошибаюсь?
второй const для PROGMEM, чтоб массив указателей тоже во флэше лежал.
const char *const - константный указатель на константные данные.
А вот это
const char* array[]
значить только то, что ты array присвоить ничего не можешь в программе потом
ЗЫ. как я люблю фонНеймана и его архитектуру. С децтва прям. А этих гарвардских умнеков - нинавижу.
Пойду пить
Погодите квасить с утра! В этой теме ещё до самого забавного и не добрались :)))
Попробуйте взять свой изначальный код со словом PROGMEM в описании массива и без этого слова. Скомпилируйте оба варианта и сравните количество замнимаемой программной памяти :)))))))
второй const для PROGMEM, чтоб массив указателей тоже во флэше лежал.
Нет, это первый const для PROGMEM. А второй const ты смело можешь убрать и класть массив в PROGMEM - второй конст для этого не нужен, попробуй.
Попробуйте взять свой изначальный код со словом PROGMEM в описании массива и без этого слова. Скомпилируйте оба варианта и сравните количество замнимаемой программной памяти :)))))))
значит я в сообщении #12 был прав - нет смысла класть указатели во флеш. Правда сделал я это не от большого ума, а от лени, но все равно приятно :)
значит я в сообщении #12 был прав - нет смысла класть указатели во флеш.
Почему нет? Сравните там же расход оперативной памяти. Со словом PROGMEM он меньше.
Мой-то иезутсякий вброс был не про оперативную, а именно про программную память.
Мой-то иезутсякий вброс был не про оперативную, а именно про программную память.
А, ну это я тоже как-то тестировал. Помещение чего-либо во флеш - очень неэкономная операция, например короткие строки класть во флеш крайне невыгодно, за выигрыш пары байтов оперативки платишь десятками и даже сотнями байтов флеша...
Сейчас не могу проверить этот пример, нет компилятора под рукой.
c PROGMEM
// const char *const DoW_Array[] PROGMEM= { dow00,dow01,dow02,dow03,dow04,dow05,dow06 };
а так так этот массив относится к инициализированным данным, то он и во флэше хранится тоже и плюс копируется рантаим библиотекой в ОЗУ при старте, поэтому занятая память программ не изменилась
у меня то вопрос, в чем разница для компилятора параметры-непосредственные константы и переменные, почему в первом случае адрес строки вычисляется правильно, а во втором - нет
даже вот так - неправильно
Так Вам же всё объяснили. Если компилятор может вычислить нечто - он вычисляет и подставляет готовую константу. То, что у Вас это вызов функции, и даже не инлайн - ему плевать с высокой колокольни - если может, то вычислет и подставляет готовый результат. Что Вы и наблюдаете.
Я как-то про такие особенности оптимизации долго объяснял одному, прости Господи, википедику ... сам по себе срач - дерьмо голимое, но там был очень красивый пример, как компилятор заменил вызов РЕКУРСИВНОЙ (!!!!) функции на готовый результат! О как! Там правда функция была инлайн. Сейчас я специально проверил без инлайн. Смотрите
Скомпилиркуйте это в IDE 1.8.1 с опциями "из коробки" и дизассемблируйте. Получите функцию setup вот такую:
и ВСЁ! Как видите он просто выбросих нахрен функцию fact, а вместо вызова fact(5) вставил готовый результат 120.
Ппоробуйте сами скомпилировать и посмотреть, чтоб уж не сомневаться.
Нравится современная оптимизация?
Насчёт опций - это важно. Разумеется, если убрать оптимизацию, то ничего такого не будет.
Спасибо Вам за науку, а компилятору - за оптимизацию.
Тему можно закрывать.
Не готов я еще для С++.
Красиво. А если убрать из описания параметра const - тоже соптимизирует? Как-бы указалово const обещает что функция будет получать только константы времени компиляции. Вполне разумно скомпилять функцию и попытаться её вызвать дабы получить результат ещё на этом этапе.. а вот ежели нету const?
Сам пока проверить не могу, но интересно..
Убрал const, заодно и костанту заменил на переменную. Ничего не изменилось
Результат
Как-бы указалово const обещает что функция будет получать только константы времени компиляции.
Что за дичь? Ничего такого const не обещает, он лишь гарантирует, что входящий параметр, помеченный квалификатором const, не будет изменён внутри функции. Константы времени компиляции - тут не при делах, от слова "совсем".
Нашли проблему.. Вытягую из исходников контролера самогонного и либок. Проверено, работает.
Человеческим языком, в drawStringPP передаем указатель на массив в PROGMEM указателей на строки в PROGMEM. И индекс в этом массиве. Копируем указатель с заданым индексом и передаем его в drawStringP, там уже все просто, ну былобы просто если б лямбда не затесалась ;) но из песни слов не выкинеш, так в либе. И такое часто пользую.
В стартовом ситуация очевидна, если компилятор при компиляции может оптимизировать и извлечь указатель на строку - работает, иначе нет и нужно явно выцарапать этот указатель из PROGMEM.
Сорри, неверно выразился, ЕвгенийП меня понял верно, пасибки.
Ну и? Получается что 13-й тип оптимизации (глобальная оптимизация потока управления по анализу потока данных) уже по сути внедрен в компиляторы, остается ждать когда памяти хватит на 14-й - глобальная оптимизация потока данных .. когда кумпилятыр станет способен самостоятельно преобразовывать разную муть из комплекта переменных, массивов и объектов в то, что посчитает лучшим решением .. а там, недолго ждать когда оно само и кодить начнет. :)
Здравствуйте.Проблема с кирилицей.Это работает.
Этот не работает.
Плата нано китайская
Что это и о чем это... в чем разница... кто это писал... для чего.... ?
Разница в String1.По задумке будет выводить сообщения на OLED0.96.Скетч из стандартных примеров,кроме сообщений естественно.
Обождите тему закрывать, у меня тоже вопрос имеется, как и у Симеона...
Вопрос простой: как приструнить компилятор (может есть какая pragma) чтобы он не развлекался с самостоятельной оптимизацией оператора switch? А то у меня как-то всё непредсказуемо получается в этой Arduino IDE: условно 8 шт. case - 8*N байт в прошивку, добавляешь еще один - получаешь 9*N + K , где K - вообще не меньше N. Ну или иногда 10 шт. нормально, а на 11-й - приплыли. Никакого порядка.
В case всё просто может быть - обычные присвоения, по одному на каждую ветку. И кейсы вроде все последовательно делаю, чтобы они ровненько легли - от '1' до '9', например.
Сначала меня всё это очень удивляло (в ассемблерную декомпиляцию, извините, не впадал), но потом прочитал https://embeddedgurus.com/stack-overflow/2010/04/efficient-c-tip-12-be-wary-of-switch-statements/ и понял, что это вроде как англичанка гадит. Теперь я в замешательстве. if-ы не хочется городить, таблица перекодировки не совсем подходит к задаче, а со switch непредсказуемость полная.
Здравствуйте.
Доброе утро!
Проблема с кирилицей.
Позвольте уточнить, каким боком это относится к теме топика?
Как и у первого автора проблема записать и считать PROGMEM
sadman41, а нельзя пример привести, а то я не до конца понял о каком случае Вы говорите.
Статью Джонса прочитал, позабавило выражение "some sense of machismo" - оно в данном контексте очень точное. Человек, вместо того, чтобы почитать стандарт языка и прокачать свои знания о нём, затевает экспериментальное исследование и через весьма непростые эксперименты с удивлением узнаёт, что оказывается порядок проверки case-меток в языке не определён. Вообще-то, он мог узнать об этом просто читая стандарт. Сам люлю такие вещи, но должен признать, что это и есть то самое: "some sense of machismo" :)))))
Как и у первого автора проблема записать и считать PROGMEM
Во-первых, у него проблема не записать и прочитать, это он может, а "понять почему работает именно так".
Во-вторых, Ваша проблема связана не с чтением progmem, а непониманием как устроена кирилица. Вот здесь человеку вроде всё объяснили (и вообще, воспользуйтесь поиском - проблема кириллицы столько раз пережёвана уже!).
В-третьих, если Вы перейдёте в адекватную тему, с удвольствием с Вами поговрю (и не один я), но пожалуйста, прекратите зафлуживать эту - она не о кириллице.
тоже интересно, есть ли какая #pragma, чтоб вырубить оптимизатор хренов конкретно для данного одного файла. У меня, помню целый while из loop-а выкинул, а я пока допер своими синими мозгами, 3 ящика виски выпил.
тоже интересно, есть ли какая #pragma, чтоб вырубить оптимизатор хренов конкретно для данного одного файла.
#pragma GCC optimize ("string"...)
Вот. Я Вас сердечно и категорически благодарю.
Проверил. Работает.
опция #pragma GCC optimize "O0"
делает из 8106 байт программы аш 9214.
sadman41, а нельзя пример привести, а то я не до конца понял о каком случае Вы говорите.
Вот, к примеру (на моем дефолтово настроенном IDE 1.6.11):
Без case 5 и 6 - "Sketch uses 1,984 bytes" с case 5 "Sketch uses 1,990 bytes" (6 байт разницы), с сase 6 "Sketch uses 2,012 bytes" - разница уже в 22 байта. Начинаем добавлять case 7, case 8 такого же типа - по 6 байт накидывается. Потом опять скачок может быть.
Я, конечно, понимаю, что сейчас как-будто пытаюсь определить причину сбоя ОС по миганию индикаторов жестких дисков... В принципе мне это жить не мешает, но когда прошивка уже еле лезет в МК и тут тебе switch свинью начинает подкидывать - хотелось бы знать, как ему по сусалам-то дать.
делает из 8106 байт программы аш 9214.
И это не может не радовать! :))))))))
Да. Значит деффективный оптимизатор не отрезал всё, до чего дотянулса.
Не люблю, када у оптимизатора мозгов больше, чем у мня.
Ну, это (скачки) как раз его естественное поведение. Если нужно его избежать, то это надо решать либо таблицей (в данном примере просто сама просится), либо макросами SWITCH и CASE, которые прячут под собой if и else if.
Со свитчем есть гораздо худшая задница - когда в операции сравнения с меткой присутствует побочный эффект, то результат вообще в общем случае неопределён - вот это совсем беда.
Проверил на коротком примере - if-else-if дает более предсказуемый результат, конечно. И progmem чуток поменее занимает. На досуге попробую замастрячить в реальной функции - даст ли это существенный выигрыш... Хотя, конечно, мне очень нравятся вот эти прекрасные case без break, которые нужно как-то превращать в if (condition || condition), если ориентироваться на замену оператора switch() макросом.
Ну, это (скачки) как раз его естественное поведение. Если нужно его избежать, то это надо решать либо таблицей (в данном примере просто сама просится)
Это просто тестовый скетч. В полноценных и вызовы функций есть в case и сочетания значений, которые невыгодно, на мой взгляд, укладывать в таблицу, если только не придумывать какой-нибудь аналог hash array.
Побочный эффект в результате какого использования case? Даже представить боюсь.