While компилируется в вечный цикл

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Аватара пользователя
Волосатый
Сверлит текстолит когтями
Сообщения: 1288
Зарегистрирован: Пн апр 14, 2008 12:54:35
Откуда: Город ГЕРОЙ Ленинград
Контактная информация:

While компилируется в вечный цикл

Сообщение Волосатый »

Доброго времени суток. Cтолкнулся с такой проблемой, код вида

Код: Выделить всё

while (flag){};
компилируется в вечный цикл, ассемблерный код этой строчки выглядит так:

Код: Выделить всё

08004242: ldrb r3, [r4, #0] 
08004244: cmp r3, r5 
08004246: bne.n 0x800424a 
08004248: b.n 0x8004248
Погуглив выяснил, что команда "bne.n" это переход, если z = 0, а команда "b" - безусловный переход.
То есть получается, если flag = 0 и мы заходим в цикл ожидания, процессор сразу из него выходит, а если зайти в цикл, когда flag отличается от нуля, мы попадем в вечный цикл. Такая история появляется только в одной большой функции, где нужно после получения команды с юсарт подождать, пока не завершится какое-то действие. в программе у меня много где такой цикл используется, но никогда не было проблем.
Объявление переменной:

Код: Выделить всё

volatile u8 flag = 0;
Волатильная, не волатильная - ничего не меняется. flag гарантировано возвращается в 0 по ходу работы программы (смотрел дебаггером).
Среда CooCox 1.7.6, gcc 4.8 2014q3
Опыт приходит сразу после того, как он был нужен...
Реклама
Аватара пользователя
uldemir
Друг Кота
Сообщения: 7359
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Re: While компилируется в вечный цикл

Сообщение uldemir »

Проверьте "видимость" этой переменной. Не случается ли так, что меняется одна локальная, а опрашивается другая локальная переменная с тем же именем. Чудес не бывает. А подобные баги компилятора вылавливаются на уровне альфатестирования. И переменная должна быть волатильной, иначе оптимизатор её примет равной нулю всегда.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Реклама
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18561
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: While компилируется в вечный цикл

Сообщение ARV »

:facepalm:
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15574
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: While компилируется в вечный цикл

Сообщение BOB51 »

Так правильно и скомпилировалось - ежли flag равно нулю - прыгаем за пределы цикла.
8)
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
Волосатый
Сверлит текстолит когтями
Сообщения: 1288
Зарегистрирован: Пн апр 14, 2008 12:54:35
Откуда: Город ГЕРОЙ Ленинград
Контактная информация:

Re: While компилируется в вечный цикл

Сообщение Волосатый »

Еще раз. Флаг волатильный, = 0 в его инициализации, в процессе работы программы он меняется 10000000%
У меня не только с этой переменной проблема.

Добавлено after 5 minutes 59 seconds:
Так же этот косяк всплывает со строчкой

Код: Выделить всё

while (mseconds >= 98){};
Ассемблер тот же, проваливается в бесконечный цикл, если на момент попадания в цикл, mseconds больше или равен 98.
Эту переменную так же делал волатильной, а инициализация нулем отсутствует.
Опыт приходит сразу после того, как он был нужен...
Реклама
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: While компилируется в вечный цикл

Сообщение Аlex »

Волосатый, Вы нам рассказываете про чудеса. volatile должен (даже обязан) решить эту проблему, причём независимо от того, чем инициализирована переменная.
Реклама
Аватара пользователя
Волосатый
Сверлит текстолит когтями
Сообщения: 1288
Зарегистрирован: Пн апр 14, 2008 12:54:35
Откуда: Город ГЕРОЙ Ленинград
Контактная информация:

Re: While компилируется в вечный цикл

Сообщение Волосатый »

Ну я же не придумываю...
Вот нагляднее пример.

Код: Выделить всё

void usart(void){
volatile sec_tmp;
...
...
switch (comand){
case TSET:
   sec_tmp = ds3231_rtc_data.seconds;
   // ТУТ ЗАПИСЫВАЕТСЯ ВРЕМЯ
   while (sec_tmp == ds3231_rtc_data.seconds);   // ожидаем, пока в прерывании не поменяется время
   // ОТСЫЛАЕМ ОТВЕТ
   break;
}
}
На первый раз выполняется правильно, на второй раз виснет на ожидании.
:facepalm: Спасибо за внимание, сделал ds3231_rtc_data.seconds тоже волатильной и оно заработало.

А с флагом хз что было)) но тоже работает. Магия какая-то.
Опыт приходит сразу после того, как он был нужен...
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: While компилируется в вечный цикл

Сообщение Reflector »

[uquote="Волосатый",url="/forum/viewtopic.php?p=3616997#p3616997"]Спасибо за внимание, сделал ds3231_rtc_data.seconds тоже волатильной и оно заработало.[/uquote]
У тебя в цикле может меняться ds3231_rtc_data.seconds, а sec_tmp не может, она вообще локальная, ее извне никак не поменяешь, потому второй volatile лишний.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: While компилируется в вечный цикл

Сообщение VladislavS »

Ну вот, так всегда, как начинают код светить, так чудеса куда-то сами растворяются...
Аватара пользователя
Волосатый
Сверлит текстолит когтями
Сообщения: 1288
Зарегистрирован: Пн апр 14, 2008 12:54:35
Откуда: Город ГЕРОЙ Ленинград
Контактная информация:

Re: While компилируется в вечный цикл

Сообщение Волосатый »

У меня логика была такая, что sec_tmp мы только что приравняли к ds3231_rtc_data.seconds и тут же их сравниваем, компилятор то не знает, что ds3231_rtc_data.seconds может где-то измениться.
Опыт приходит сразу после того, как он был нужен...
Аватара пользователя
qbit
Встал на лапы
Сообщения: 101
Зарегистрирован: Вт апр 02, 2013 10:03:29
Откуда: Санкт-Петербург
Контактная информация:

Re: While компилируется в вечный цикл

Сообщение qbit »

Ваша беда в поголовном использовании while. Переходите на иную стилистику программирования - программные автоматы.
Поясню на пальцах на вероятный "баг" в приведенном Вашем фрагменте кода.

Код: Выделить всё

   // ТУТ ЗАПИСЫВАЕТСЯ ВРЕМЯ
Вы уверены, что тут изменилась переменная ds3231_rtc_data.seconds. Но т.к. работает с внешнем тайкиппером, то Вы должны допускать вероятность, что переменная может не измениться и Вы попадете в while .
Для связи email: info собака qbit.su
Ответить

Вернуться в «ARM»