if () {} else {}
- Войдите на сайт для отправки комментариев
Вопрос простой. До какой степени вложенности можно доводить данный оператор?
if (набор условий) { if (набор условий) {команды;} команды; } else if (набор условий) { if (набор условий) {команды;} else {команды;} if (набор условий) {команды;} команды; команды; команды; } else if (набор условий) {команды; команды; команды; команды;} else {команды;}
структура моего кода схожа, в одной из функций происходит множественное ветвление с проверкой кучи условий в основном соединённых логическими операторами. код работал нормально, но в какой то момент усложнения (добавления каких то строк) стал выдавать побочные неожиданные результаты. происходит выполнение блоков условия для выполнения которых не выполнены (т.е. исключены вышестоящим оператором проверки условий). и присвоение некоторым переменным значений, возникновение которых не возможно без некорректного зацикливания или неверного обращения к памяти. (типа: i=1;,2;,3,;4;,10;, в отдельных условиях i++; и вдруг появляются значения i=250;).
сталкиваюсь с такой белибердой не первый раз, в предыдущих случаях подобные блоки переписывались с нуля с упрощением струкруры или выносом отдельных групп условий в отдельные функции (что нифига не на пользу экономии памяти). Прямо сейчас оригинал скетча выгрузить не могу
> До какой степени вложенности можно доводить данный оператор?
Никогда не слышал о каких-либо ограничениях. По идее, если компилятор писали грамотные люди (а это обычно так :) - не должно быть вообще. Это же, в конечно итоге, все jump-пы просто транслируется. В отличает от вызова функций стек при этом - не увеличивается.
Так что скорее всего, все-таки ошибка где-то у вас. Раз логика "замудренная", то и промахнутся с закрывающей скобой все шансы есть. Или еще что-то (случаной i присвоили, с указателями напутали, вышли за границы массива/буфера и т.п.)
Если скетч большой - может оперативка закончилась. Тогда тоже любые чудеса возможны. Ну и, теоретически, камень бракованный может быть. Но это уже "сильно теоретически", ошибка в коде на порядки вероятней.
>что нифига не на пользу экономии памяти
Зато на пользу сопровождаемости и читабельности кода. А это тоже очень важная храктеристика, не менее важная чем "что-бы работало". Неужели у вас уже действительно счет памяти "на байты" идет? Уверены что не занимаетесь преждевременной оптимизацией?
Да и, возможно, можно как-то по другому все "замутить", что-бы небыло этой тучи ветвлений. Какой-нибудь автомат состояний, pattern matching и т.п. Вообщем попытатся сделать логику более простой. Но не сколько для "экономии памяти", сколько для "более прозрачного кода".
>Прямо сейчас оригинал скетча выгрузить не могу
А без этого можно только "абстрактно теоретизировать".
если у вас есть проверка множества условий,почему бы не воспользваться оператором switch() case - этот оператор просто создан для подобного рода заданий))и читабельности ,там так же на каждый case можно определить выпонения нескольких операций ))
все скобки пересчитал первым делом, т.е. буквально каждую выделял и смотрел что она открывает или закрывает. присвоения по подозрительной переменной несколько раз пролистал с помощью поиска (бывало, что вместо проверки условия == появлялось =, но не в этот раз). switch() case совершенно не подходит, он сможет заменить лишь первый уровень if () else{}. переполнение переменной определённой как байт дождаться не тяжело, но только при неправильной работе кода. к нано уже зацеплены SPI экран, кардридер и часы. всё это только в виде библиотек не слабо хавает память. вывод на экран это строки, флешка тоже, часы тоже не пустышка. да плюс всё моё написанное. буду разбивать на функции, если заработает, значит компилятор таки кривой.
>буду разбивать на функции, если заработает, значит компилятор таки кривой
Скорее всего поможет. Но не потому что "компилятор кривой" (в лотерию IMHO вероятней миллион выиграть), а потому что переписывая, да еще более читабильным видом вы с большой долей вероятности не повторите ту же самую ошибку.
>все скобки пересчитал первым делом
Ну так скобки это же только "один из возможных" способов :) Еще десяток способов "выстрелить себе в ногу" имеется.
А switch, на самом деле, в сочетании с подходом "автомат состояний" может сильно упростить логику. Если и не полностью избавить от if-вов, то сократить их кардинально, а оставшиеся сделать "тривиальными". Но естесвенно это потребует "смены алгоритма". Просто "вместо if использовать switch" либо ввобще не выйдет, либо будет еще более "монструозно".
И померяйте оставшуюся память (пару дней назад были ветки где это обсуждалось, давал там линки). Раз у вас "куча всего", то шанс совсем не маленький что причина в нехватке оперативки. Причем если вы сейчас "перепишите на функции" и оно заработает, то это может означать только что баг "случайным образом" переместился куда-то в более незаметное место. И когда и куда вылезет - не известно.
да, тему про память видел, но руки ещё не дошли. хотя вероятно в любом случае буду аппаратную базу менять. слишком много подводныз камней для неопытного программиста даже при работе с часами DS1307, не говоря уж о цветных многопиксельных экранах
>слишком много подводныз камней для неопытного программиста
Ну Си она такая :) Большая свобода, но и большая отвественность.
>не говоря уж о цветных многопиксельных экранах
Да. Тут память лишней не будет.
Может покажете свой скетч? Вдруг углядим ошибку какую.
откомментирую работу.
на старте выводится версия кода, далее в цикле начинает читаться и выводится на LCD текущие дата и время.
при долгом нажатии на на клавишу"1" разворачивается главное меню. на данный момент 1й пункт установка времени, 2,3,4. не заняты. клавиши 2,3 -вверх/вниз 4-ок. 5-ошибка чтения нажатия клавишь, 6-9 соответственно долгие нажатия соответствующих клавишь.
при выборе пункта "1. time" разворачивается подменю. пункты часов от года до секунды. параметры изменяются аналогично курсорным методом. выход в главное меню долгое нажатие клавиши "1", и одновременно записывает в часы новые данные. выход в основной экран (в котором кроме часов пока ничего нет) аналогично.
всё работает как задумано, однако если в главном меню выбрать пункт "2. " - резерв, то получаю косяк. появляется курсор из подменю часов, а статус меню menu_stat (одновременно и курсор и указатель) получает значение на данный момент не существующее. (число 250 за один цикл работы функции вроде просто неоткуда взять)
Вечерком попробую посмотреть подробней, но присмотритесь к строчке 311 и 318.
Втыкните там Serial.print посмотрите что там происходит. Возможно что 250 это не "сильно увеличенная", а наоборот "сильно уменьшенная" menu_stat . Если она была 0, а вы от нее отняли 1, то получите 254 (она же беззаковая), потом еще парочку отниманий и имеем искомую 250.
Но то что это не проблема "вложенности if" - это точно. Никакго "сверх-глубокого вложения" - у вас нет и в помине.
Код немного "заспагечен" и стоило бы его "причесать" (убрать "магические цифры", где-то switch "просится", где-то массивом можно, где-то дублирование кода...), но к чему-то "фатальному" это не должено приводить.
Так что либо "искать ошибку" (вероятней) либо "проверять сколько оперативки".
так у этого кода в любом случае одна дорога - в архив, на память об ошибках молодости. в этом скетче нужно ещё изучить и отработать начальные умения по работе с SD карточкой и чтоб оно не конфликтовало с остальным, возможно ещё подвесить датчик температуры. если оставшихся 10к памяти хватит.
а блок контроля Serial я перетащил с 300х строк на 169ю, результат во всех точках одинаковый, переменная изменяет своё значение скачком, вероятно выполняется строка 326 (щас углядел единственную возможность), но как получается, что она выполняется - непонятно
>так у этого кода в любом случае одна дорога - в архив
Ну почему. Потренероватся на нем в результатах чтения книг типа "Совершенный код" и "Ремесло программиста" - очень даже можно. Не всегда можно "все переписать с нуля". Так что уметь "приводить код в чувство" - нужно. Тем боле что "писать сразу красиво всегда" - не возможно как бы не хотелось. Да и иногда "быстро" важнее чем "красиво". Чисто проверить идею. Если "заработало", тогда уже и про оптимизации с красивостями думать можно.
>если оставшихся 10к памяти хватит.
Уй. Вы натурально ошибаетесь. У самой жирной меги памяти всего 8KB. Вы скорее всего спутали с "флеш памятью" (это то что показывает как "размер скетча"). Флеш - это аналог компьютерного "винчестера" где скетч хранится при выключении. А при подачи питания он копируются в RAM. Если не хватит флеша - скетч просто не зальется, если не хватит памяти (RAM) - ребуты, зависы и магические глюки.
Но мне кажется дело все-таки не в памяти . У вас скетч не такой уж большой, я не проверял сколько там жрет библиотека экрана и часов, но за рамки чего-то экстраординарного - ваш скет не выходит. Куча примеров работающих подобных.
>а блок контроля Serial я перетащил с 300х строк на 169ю,
Не понял что вы куда перетащили. Но навтыкайте дополнительно Serial.print везде где вы изменяете menu_stat. Особенно где уменьшаете (не заметил 326 строку) . Можете по два раза "до изменения" и "после". Задетекте четко место где происходит "скачок", потом будете выяснять "а как оно туда попадает" (тем же способом - тыкаем Serial-принты. Можно к ним добавлять еще какую-то строку, что-бы было легче понять "какой именно принт гавгнул").
> 10к
да, я имел в виду именно флешную память.
с Serial.print поразбираюсь
Думаю примерно такая функция может помочь