Инициализация переменных
- Войдите на сайт для отправки комментариев
Втр, 21/03/2017 - 23:34
Вопрос, быть может, детский и кое-кто увидит в нем ошибку ДНК, но всё же. Есть упрощенный код такого плана (значения переменных взяты с потолка):
void test(uint8_t _nor){
//uint8_t dropResult = 55;
uint8_t dropResult;
Serial.print("[1] dropResult: "); Serial.println(dropResult);
if (_nor == 17) {
dropResult = 8;
Serial.println("[*] if");
}
Serial.print("[2] dropResult: "); Serial.println(dropResult);
}
void setup() {
Serial.begin(9600);
test(18);
}
void loop() {}
Так, как переменная dropResult не инициализируется (варнинги я видел), я ожидаю увидеть в первом Serial.println() произвольное значение, которое оставлено предыдущей функцией, получавшей эту ячейку памяти. И в том, что сразу после условия - точно такое же. Может, конечно, это наивное желание. Потому что вот, что показывает мне Serial Monitor:
[1] dropResult: 0
[2] dropResult: 8
Т.е. Serial.println() из if() не выполняется, а присвоение - вполне себе. При инициалилизации в момент объявления переменной такого эффекта нет.
Перепроверил код не раз. Перенес в CodeLite (в нем такой же компилятор, что и в Arduino IDE) - там всё нормально, в обоих строчках выводится значение переменной равное нулю.
Вопрос: что это - моё непонимание стандарта, криворукость, проблема с компилятором или проявление того самого пресловутого нечестного Си, после использования которого серебрянные ложки пропадают?
Посмотред дизассемблер кода. Оптимизация сделала так
void test(uint8_t _nor){ Serial.print("[1] dropResult: "); Serial.println(0); if (_nor == 17) { Serial.println("[*] if"); } Serial.print("[2] dropResult: "); Serial.println(8); }Т.е. переменной вобще нету! Раз значение задается константой для одной из веток if а в других оно не определено, то для неопределенной ветки компилятор вправе выбрать любое ему понравившееся, а выбрав константу 8 можна сократить код. Так он и сделал. Если в Вашем примере заменить стр.07 на dropResult = 8+millis(); то компилятор лишается счастья сократить код константной оптимизацией, ему приходится заводить переменную dropResult которую он инитит 0, т.к. чем бы ни инитил - сократить не получится. Эффект пропадает и видим
[1] dropResult: 0
Про право обходится с неинициализированной переменной как угодно я читал, конечно. Но меня смущал тот факт, что переменную я, в сущности, использовал до if() и под нее уже должна быть выделена память (по моим понятиям). А так же добивало то, что в CodeLite всё происходило корректно при том, что компилятор один и тот же. Получается, что так параметры оптимизации сказываются (видимо различны в обоих случаях)?
История-то эта началась с того, что я в каком-то англоязычном интернет-руководстве по оптимизации кода для микроконтроллеров прочитал, что те, кто инициализируют объявленные переменные нулем - зря растрачивают progmem space и собственное время. Решил проверить - верно ли такое утверждение для МК, который оказался под рукой...
UPD: и я не совсем понимаю, что такое для компилятора "неопределенная ветка [оператора if]", ведь указание на обязательное применение else отсутствует. В итоге if() должен просто превратиться в JNE какой-нибудь, как я понимаю и не более того. Запись же в ячейку памяти не произвольного значения, а явно находящегося в невыполняемом блоке - уже за гранью добра и зла ))
sadman41, в неиниализированной переменной может находиться всё, что угодно и никто не гарантирует, что там будет находиться что-то постоянное - имеет право меняться. Просто "всё, чо угодно" - значение не определено и никто Вам ничего не гарантирует. Именно это Вы и наблюдаете.
меня смущал тот факт, что переменную я, в сущности, использовал до if() и под нее уже должна быть выделена память
Даже если так, и что? Никто Ва не гарантирует ни разумного значение в этой памяти, ни того, что она будет оставаться неизменной - там случайный мусор, уж какой получился.
в CodeLite всё происходило корректно
Здесь тоже всё абсолютно корректно. Значение не определено и может быть каким угодно. В чём некорректность?
те, кто инициализируют объявленные переменные нулем - зря растрачивают progmem space и собственное время.
Это верно для тех, кто программирует на ассемблере или с выключенной оптимизацией, т.к. память при загрузке и сама заполняется нулями.
С оптимизатором не всё так однозначно. Чаще всего он не будет вставлять код инициализации нулём, но и гадить в переменную не будет, вот всё хорошо и получится.
Запись же в ячейку памяти не произвольного значения, а явно находящегося в невыполняемом блоке - уже за гранью добра и зла ))
Никаких граней. Вы странно пнимаете выражение "произвольное значение". Чем по Вашему значение "явно находящееся в невыполняемом блоке" не произвольно? "Произвольное" значит, что там будет что-то, что туда по каким-то причинам попало и не более того.
переменную я, в сущности, использовал до if() и под нее уже должна быть выделена память (по моим понятиям).
константная оптимизация как раз и предполагает не выделять память на переменную если можна обойтись константой.
Получается, что так параметры оптимизации сказываются (видимо различны в обоих случаях)?
да.
История-то эта началась с того, что я в каком-то англоязычном интернет-руководстве по оптимизации кода для микроконтроллеров прочитал, что те, кто инициализируют объявленные переменные нулем - зря растрачивают progmem space и собственное время.
Да. Но это относится только к глобальным переменным, ну и статическим, которые по сути глобальные с ограниченой областью виденья. Компилятор собирает их в отдельную секцию, т.е. непрерывную область в памяти и при старте контроллера одним циклом записывает 0 во всю область. Локальные переменные надо всегда инитить ручками. Причем отсутствие их инициализации - источник большого кол-ва неприятных (т.к. иногда нестабильных и невоспроизводимых) ошибок.
UPD: и я не совсем понимаю, что такое для компилятора "неопределенная ветка [оператора if]", ведь указание на обязательное применение else отсутствует.
В итоге if() должен просто превратиться в JNE какой-нибудь, как я понимаю и не более того.
ага. так. стр.16 только обход вызова
Serial.println("[*] if");Запись же в ячейку памяти не произвольного значения, а явно находящегося в невыполняемом блоке - уже за гранью добра и зла ))
Из кода видно - нету переменной, нету ячейки, только константы, только хард ;) В r17 параметр _nor и все.
там всё нормально, в обоих строчках выводится значение переменной равное нулю.
и '0', и '8' - являются произвольными значениями.
если ожидается, что это значение определено, то оно явно не произвольно.
Иду я по улице спокойно, потом раз - и очухиваюсь в КПЗ, без кошелька и в наручниках. Потом следствие выясняет, что я не высказал возражений местному гопнику Арсению по поводу того, чтобы мне били по голове сзади и тырили наличность, а так же, пока лежал, не возражал по поводу того, чтобы сотрудник 3-го отделения Л. насыпал мне в карманы патронов с целью выполнения плана по задержаниям особо опасных преступников. Простая оптимизация же - бегать ни за кем не надо, клиент лежит в луже. Со всех сторон логично ))
Вобщем, спасибо товарищи, механизм срабатывания этого "крекс-пекс-фекса" я понял - простое невыделение ячейки памяти, а не помещение в нее значений (как разумных, так и неразумных) и последующее их изменение по избранному компилятором алгоритму до момента явной инициализации.
Иду я по улице спокойно, потом раз - и очухиваюсь в КПЗ, без кошелька и в наручниках.
простое невыделение ячейки памяти, а не помещение в нее значений
параноидальная настойчивость превратить произвольное значение в определённое.
если бы так и было, то в описании произвольного значения было бы примечание про ячейки памяти или кошелёк.
А после этой фразы еще и дислексия ))
Сотру, пожалуй, IDE. Буду пускать слюну и строгать палочки.
механизм срабатывания этого "крекс-пекс-фекса" я понял - простое невыделение ячейки памяти, а не помещение в нее значений (как разумных, так и неразумных) и последующее их изменение по избранному компилятором алгоритму до момента явной инициализации.
Не поняли. Не хочу тратить время на составление примера, но поверьте, вполне допустима ситуация, когда память выделяется, но до инициализации используется как временный буфер для промежуточных значений.
Всё, что Вы должны понять: у программитса нет никаких оснований ожидать какого-либо значения (равно, как и отсутствие какого-либо значения) в неинициализированной переменной.
Больше тут понимать нечего.
Брат! Если у тебя включен оптимизатор, то память не выделена в момент декларации. Так - по стандарту положено.
Следствие этого - разные значения неинициализированной переменной в разных местах кода. Считай, что это каждый раз - случайное число.
Если ты хочешь иметь, пусть случайное, но всегда одинаковое число, то память должна быть выделена. Значит отключи оптимизатор. Или используй статик (или глобал). Под них компилятор выделит память в момент декларации (скорее всего ;) ).
---------------
прочел пост Евгения. И так тоже возможно.
А после этой фразы еще и дислексия ))
Сотру, пожалуй, IDE. Буду пускать слюну и строгать палочки.
таки, это патология - ты подсознательно уверен, что тебя будут уговаривать использовать avr-gcc ?
*реакция форумчан не определена: от хоть убейся ап стену, до удачи в пешеходной экскурсии в счастье.
Товарищи, я понимаю, что по местной традиции в любой теме нужно устроить срач, потом спросить чей Крым и исписать еще страниц сто.
Я уже увидел, что в данном конкретном случае именно оптимизация (в целом) приводит к тому, что логическая структура, написанная на языке C++ не переводится в asm, как я этого ожидал. Спасибо всем помогавшим разобраться.
Да, я не настоящий программист, а поддельный (всех обманул и пробрался в святая святых с корыстной целью) - теперь Тува будет наконец-то полностью завалена обломками и залита керосином. На унитаз я сажусь не проверяя есть ли в бачке вода и в душ залезаю без проверки наличия шампуня во флаконе (ожидаю, что все на месте). Перед тем, как сажусь в машину, не делаю лабораторных исследований на предмет соответствия заданным параметрам сцепления шины с грунтовой поверхностью (ведь кто знает, как изменилась структура покрытия колеса за то время, пока я спал). Не знаю, сможете ли вы меня простить за это. Ну, или хотя бы понять.
И, Клапауций, - я просто тобой манипулирую чтобы ты стал меня уговаривать использовать avr-gcc. Это же очевидно.
Иду я по улице спокойно, потом раз - и очухиваюсь в КПЗ, без кошелька и в наручниках. Потом следствие выясняет, что я не высказал возражений местному гопнику Арсению по поводу того, чтобы мне били по голове сзади и тырили наличность, а так же, пока лежал, не возражал по поводу того, чтобы сотрудник 3-го отделения Л. насыпал мне в карманы патронов с целью выполнения плана по задержаниям особо опасных преступников.
А нефиг было ходить в тот район, о котором Вас заранее предупреждали, что пребывание там может быть опасно для Вашего здровья и жизни.
Надеюсь, аналогия понятна.
PS. Но вообще пример, конечно, интересный.