Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Лучшее - враг хорошего?
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
KnightIgor
Привет, коллеги.

Следующая предыстория. Есть работающая, но и далее развиваемая программа на STM32F103RC на собственном железе. В ней много всего: поддержка FlashFS на microSD через SPI и на EEPROM через I2C, комбинированное USB устройство (HID/CDC/MassStorage), два радиомодуля на CC1101, и т.п. В какой-то момент код созрел до такой степени, что устаканившуюся часть его я решил "слить" в библиотеку, чтобы исключить длительные перекомпиляции исходников. Для этого создал новый проект, который собирает библиотеку, а основной проект её включает.

Все пошло. И тут начались неуловимые глюки и странности. Вроде все работает, но иногда файловая система сбоит - например, вдруг носитель якобы не содержит файлов. В некоторых условиях при интенсивном обмене по радиоканалам устройство может сброситься, и т.п. Начинаю скрупулезно сравнивать проекты и вдруг натыкаюсь на факт, что мой "библиотечный" проект имеет в опциях уровень оптимизации "по умолчанию". Так как основной проект собирается с -O0 (пока отлаживаюсь, оптимизация выключена, да и память не вышла вся еще), я включил -O0 и для библиотеки и... всё заработало без проблем.

Возникают вопросы:
1. Какой уровень оптимизации у KEIL по-умолчанию?
2. Глюки программы связаны с ошибками компилятора на высоких уровнях оптимизации?
3. Мой код имеет синтаксические недостатки, которые проявляются лишь при сильной оптимизации (например, нужно ли писать для переменных static volatile или достаточно static)?
4. Можно ли "смешивать" в результирующем коде различные уровни оптимизации?
5. Как откомпилированы в смысле оптимизации библиотеки RL от KEIL?

Каков ваш опыт, коллеги?
SII
На Си, вообще говоря, не пишу, хотя кой-какие вещички по-быстрому проверял в Кейле. Volatile указывать обязательно, если переменная может быть изменена независимо от воли кода (ну или Вашим же кодом, но так, что транслятор отследить изменения не в состоянии -- например, меняете в обработчике прерывания, а используете в основной части программы). Вот при -O0 отсутствие volatile вряд ли скажется: скорей всего, компилятор тогда не пытается запоминать, какие значения он раньше грузил в регистры, и просто каждый раз заново обращается к памяти (что, собственно, и должен делать для volatile-переменных).
aaarrr
1. -O2
2. Нет
3. Возможно. Вопрос в скобках совершенно непонятен - это все равно что спросить, нужно ли объявлять переменную как volatile int, или достаточно int.
4. Можно

Описываемое поведение больше похоже на проблемы со стеком.
kovigor
Цитата(KnightIgor @ May 30 2012, 11:30) *
Все пошло. И тут начались неуловимые глюки и странности. Вроде все работает, но иногда файловая система сбоит - например, вдруг носитель якобы не содержит файлов. В некоторых условиях при интенсивном обмене по радиоканалам устройство может сброситься, и т.п. Начинаю скрупулезно сравнивать проекты и вдруг натыкаюсь на факт, что мой "библиотечный" проект имеет в опциях уровень оптимизации "по умолчанию". Так как основной проект собирается с -O0 (пока отлаживаюсь, оптимизация выключена, да и память не вышла вся еще), я включил -O0 и для библиотеки и... всё заработало без проблем.
...
Каков ваш опыт, коллеги?


Были подобные проблемы, когда не хватало быстродействия МК. В моем случае проблема решилась перепрограммированием PLL для получения макс. допустимой для LPC214x тактовой частоты (60 МГц) ...
KnightIgor
Цитата(aaarrr @ May 30 2012, 11:35) *
3. Возможно. Вопрос в скобках совершенно непонятен - это все равно что спросить, нужно ли объявлять переменную как volatile int, или достаточно int.

Описываемое поведение больше похоже на проблемы со стеком.

Пусть есть "глобальная" переменная, через которую передаются состояния между участками кода из разных *.C модулей или же переменная внутри одного *.С модуля, через которую "общаются" процедуры внутри его. Обязательно надо volatile [static] <type>?! Вряд ли, т.к. этот модификатор не встречается в общедоступном известном коде как Chan FatFS или contiki, которые, как известно, проверенно работают.

Стек вряд ли, т.к. я не выделяю ограниченую область памяти для него (путем startup_xxxx.s), а, подобно DOS wink.gif , ставлю его на самый верх имеющейся RAM. В моем проекте при 48кБ RAM используется около половины, а остальное сверху - стек. Если это действительно проблема стека, то такое должно означать, что оптимизация требует его больше, что противоречило бы идее.

Что может еще быть? Гипотеза - при вызове функции изнутри другой функции и передаче ей в качестве параметра ссылки на локальную переменную, которая как правило размещена в стеке, для "высоких" уровней оптимизации такая переменная может быть ошибочно размещена в регистре, и ссылаться будет не на что. Это был бы явно глюк компилятора.

Цитата(kovigor @ May 30 2012, 11:41) *
Были подобные проблемы, когда не хватало быстродействия МК. В моем случае проблема решилась перепрограммированием PLL для получения макс. допустимой для LPC214x тактовой частоты (60 МГц) ...

То есть, оптимизированный код работает МЕДЛЕНЕЕ, и ему нужен более производительный процессор?
Кстати, подумал о программых задержках (типа for {i = 10000; i; i--}), которые, напротив, могут оказаться слишком быстыми с оптимизацией, и недожидаться чего-либо. В моем коде я их не использую (а пользую DWT, дающий абсолютное время).
aaarrr
Цитата(KnightIgor @ May 30 2012, 15:17) *
Пусть есть "глобальная" переменная, через которую передаются состояния между участками кода из разных *.C модулей или же переменная внутри одного *.С модуля, через которую "общаются" процедуры внутри его. Обязательно надо volatile [static] <type>?! Вряд ли, т.к. этот модификатор не встречается в общедоступном известном коде как Chan FatFS или contiki, которые, как известно, проверенно работают.

Нет, не нужно.

Цитата(KnightIgor @ May 30 2012, 15:17) *
Стек вряд ли, т.к. я не выделяю ограниченую область памяти для него (путем startup_xxxx.s), а, подобно DOS wink.gif , ставлю его на самый верх имеющейся RAM. В моем проекте при 48кБ RAM используется около половины, а остальное сверху - стек. Если это действительно проблема стека, то такое должно означать, что оптимизация требует его больше, что противоречило бы идее.

Ну, если стек вне подозрений, остаются еще выходы за границы массивов, несоответствующие действительности прототипы функций и т.п.
После изменения проекта поменялось расположение данных в памяти, вот ошибки и вылезли.

Цитата(KnightIgor @ May 30 2012, 15:17) *
Что может еще быть? Гипотеза - при вызове функции изнутри другой функции и передаче ей в качестве параметра ссылки на локальную переменную, которая как правило размещена в стеке, для "высоких" уровней оптимизации такая переменная может быть ошибочно размещена в регистре, и ссылаться будет не на что. Это был бы явно глюк компилятора.

Поверьте, таких глюков точно нет.
KnightIgor
Цитата(aaarrr @ May 30 2012, 13:34) *
Нет, не нужно.

Тоже в этом уверен.

Цитата
Ну, если стек вне подозрений, остаются еще выходы за границы массивов, несоответствующие действительности прототипы функций и т.п.
После изменения проекта поменялось расположение данных в памяти, вот ошибки и вылезли.

Проект находится на активной фазе развития, меняется много чего, что наверняка приводит к постоянному перемещению кода. Тем не менее все (с -О0) работает.

Цитата
Поверьте, таких глюков точно нет.

Я бы не стал это столь категорично утверждать. Хотя бы по закону Мерфи: "Любая работающая программа содержит по крайней мере одну ошибку" со следствием "Безошибочные программы неработоспособны" wink.gif .
aaarrr
Цитата(KnightIgor @ May 30 2012, 15:49) *
Я бы не стал это столь категорично утверждать. Хотя бы по закону Мерфи: "Любая работающая программа содержит по крайней мере одну ошибку" со следствием "Безошибочные программы неработоспособны" wink.gif .

Просто слишком очевидная была бы ошибка, чтобы ее не изловили в зародыше. Посмотрите release notes - ошибки, которые исправляются от релиза к релизу, носят весьма сложный характер, просто так не наступишь.
Свои программы всегда собираю исключительно с опцией -O3. На ошибку компилятора в этой связи наступил, помнится, только однажды.
vlad_new
1. Уровень по default 0
2. Вопрос конечно интересный. Были у меня проблеммы с массивами. К примеру так: volatile char Mas[100]; В некоторых местах, при оптимизации, где
стояло выражение: Mas[0]=0; компилятор заменял его регистром. Хотя по всем кононам не имел такого права. Лечилось либо холостым чтением:
tmp=Mas[0]; либо заводил указатель на массив, либо просто через промежуточную переменную static. Причем в примитивных примерчиках такой эффект воссаздать не удавалось. Только в большом проекте, где массив используется сразу в кучу местах.
Хотя может в последних версиях KEILа уже что то и подправили.
3. В локальных только static. Если будет volatile static, то KEIL все проигнорирует и выделет либо регистр либо кусок стека. Покрайне мере так было в ранних версиях.
4. Я смешиваю.
5. Не знаю.
_Артём_
Цитата(vlad_new @ May 30 2012, 15:07) *
3. В локальных только static.


А что просто написать
Код
uint8_t tmp;
нельзя?

Обязательно писать
Код
static uint8_t tmp;
?
KnightIgor
Цитата(_Артём_ @ May 30 2012, 14:25) *
А что просто написать
Код
uint8_t tmp;
нельзя?

Обязательно писать
Код
static uint8_t tmp;
?

Речь также о "видимости" переменной между модулями. static видна только в своем модуле. Это означает, что в других можно использовать то же имя, если хочется. Не объявленная как static будет глобальной и "видна" и доступна всем модулям программы. Могут случиться казусы.

Цитата(vlad_new @ May 30 2012, 14:07) *
1. Уровень по default 0

Таки -O2. Это видно в строке ключей в итоге, как я обнаружил только что.

Цитата
2. Вопрос конечно интересный. Были у меня проблеммы с массивами.
Хотя может в последних версиях KEILа уже что то и подправили.

Вот именно на это я и "грешу". Похоже, что массивы (буферы) ведут себя странно.
aaarrr
Цитата(KnightIgor @ May 30 2012, 16:49) *
Вот именно на это я и "грешу". Похоже, что массивы (буферы) ведут себя странно.

Тогда добейтесь сперва стабильного воспроизведения ошибки. Без этого никак.

Вообще, RVCT позволяет себе некоторые "вольности" с volatile (например, выбрасывает пустые циклы вида for(volatile int n = 100; n > 0; --n)), но чтобы до нерабочего состояния довести программу - как-то сомнительно.

Характер ошибок ("иногда что-то ломается") указывает скорее на порчу данных из-за ошибки в программе.
KnightIgor
Цитата(aaarrr @ May 30 2012, 15:07) *
Тогда добейтесь сперва стабильного воспроизведения ошибки. Без этого никак.

Во-во. Именно это не получалось: лишь в одном из 10 случаев происходили какие-то странности...

Цитата
Характер ошибок ("иногда что-то ломается") указывает скорее на порчу данных из-за ошибки в программе.

Я тоже так и понял, потому поддержал "тему" массивов. Ищу...

P.S. Прикол теперь в том, что я вернул установки оптимизации в якобы проблемные, загрузил, а всё работает! Конечно, между делом кое-что развивалось в программе.
Не знаю, радоваться или огорчаться....
Albun
Была у меня когда-то тоже похожая проблема с оптимизацией (правда в IAR-е, но может и для KEIL-а это будет тоже) : без оптимизации работало нормально, а с оптимизацией появились хаотические ошибки и зависания. Причем не стабильно - здесь и сейчас - а время от времени, без никакой видимой системы. Но потом после мучительных поисков нашел так-ки причину - у меня не корректно сохранялись регистры в блоке обработки IRQ прерываний. Я не сохранял регистр R12, а как оказалось компилятор этот регистр тоже использует как регистр общего назначения, т.е. в тех процедурах в которых он используется, компилятор не генериует команды на сохранение его при в ходе процедуру и восстановлении его при выходе из процедуры (как это делается с регистрами R4-R11)
Соответственно причина была в том что без оптимизации R12 вообще не использовался компилятором, а оптимизированный код изредка использует R12. И весь хаос получался тогда, когда так стекались обстоятельства, что прерывание возникало в процедуре которая пользовалась R12. Обработчик IRQ в моем коде (MyIrqHandler) тоже компилировался (при оптимизации) с R12. А поскольку компилятор не генерирует код сохранения этого регистра при входе, то при выходе из MyIrqHandler R12 был "сбит", вот и получалось что R12 рушился но происходило это редко и хаотично.
Проверьте, может и у вас та-же проблема.

Код
IRQ_Handler_Entry:
    PUSH {R0,R1}
    MRS R1,CPSR
    BIC R0,R1,#0x1F
    ORR R0,R0,#ARM_MODE_SVC
    MSR CPSR_C,R0
              ...
    PUSH {R1-R3,LR} --> а про R12 я забыл, т.е. потом поправил так:  PUSH {R1-R3,R12,LR} /POP {R1-R3,R12,LR}
                        ^ в зависимости от того какие регистры выше R3 будут использованы в MyIrqHandler, компилятор сам их сохранит и восстановит (кроме R12
    BL MyIrqHandler (MyIrqHandler - процедура на Cи)
    POP {R1-R3,LR}
              ...
    MSR CPSR_C,R1
    POP {R0,R1}
    SUBS PC,LR,#04
EvilWrecker
Также в свое време потратил немало усилий на отыскания причн кривой работы программы после оптимизации. В результате выявились несколько эмпирических установок, например использовать volatile если есть сомнения по поводу "сохранности" переменных, а также адаптацию механизма try-catch под баг-репорт нужды: обычно это позволяет обойти некоторые проблемы, столь простые что до них нельзя вообще додуматься, хотя и с более сложными тоже неплохо справляется. Ко всему это приплюсовалось вездесущая, я бы сказал занудная работа по пре-структуризации всех мест( по мере возможного) где на ваш взгляд что то может пойти не так( инициализация переменных,указатели,проверка типов и др)- здесь очень полезно довольно большое число директив из С.

Также очень рекомендую использовать довольно полезный опыт, отраженных в стандартах на по для авионики например- хотя та же мисра уже дает много.

-
vlad_new
Я вот еще чего вспомнил. Если массив объявлен внутрии фунции как char mas[100], и при попытке вызвать из этой ф-ции другую с передачей адреса этого массива, иногда получается дребедень. При оптимизации компилятор небольшие массивы помещает в стек и передать адрес такого массива почему то не всегда выходит. Так что все локальные массивы ( от греха подальше ) объявляю как static char mas[100]. К тому же чревато, что где то, стека может не хватить. А вообще мне тут советовали всегда заводить указатели на массивы чтоб не было проблемм с оптимизатором. К тому же указатели прекрасно индексируются. Я попробывал и мне понравился такой стиль.



_Артём_
Цитата(vlad_new @ May 31 2012, 03:42) *
Если массив объявлен внутрии фунции как char mas[100], и при попытке вызвать из этой ф-ции другую с передачей адреса этого массива, иногда получается дребедень. При оптимизации компилятор небольшие массивы помещает в стек и передать адрес такого массива почему то не всегда выходит. Так что все локальные массивы ( от греха подальше ) объявляю как static char mas[100].

Вот так объявляете:
Код
void Func()
{
    static char mas[100];
    //  код
}

?
Или так:

Код
static char mas[100];
void Func()
{

    //  код
}

?

Цитата(vlad_new @ May 31 2012, 03:42) *
К тому же чревато, что где то, стека может не хватить.

Или ОЗУ не хватит.

Цитата(vlad_new @ May 31 2012, 03:42) *
А вообще мне тут советовали всегда заводить указатели на массивы чтоб не было проблемм с оптимизатором.

Это ещё зачем? Да к тому же всегда?
Где можно посмотреть на тот совет?

Цитата(vlad_new @ May 31 2012, 03:42) *
Я попробывал и мне понравился такой стиль.

Зря...
KnightIgor
Цитата(vlad_new @ May 31 2012, 02:42) *
Я вот еще чего вспомнил. Если массив объявлен внутрии фунции как char mas[100], и при попытке вызвать из этой ф-ции другую с передачей адреса этого массива, иногда получается дребедень. [...] Так что все локальные массивы ( от греха подальше ) объявляю как static char mas[100].

Я выше также написал, что у меня есть подозрения на локальные массивы. Однако делать временные внутрифункциональные массивы (и переменные вообще) статическими, а значит - перманентными в памяти, - не выход и не стиль. Более того, о реентерабельности таких функций можно сразу забыть.

Цитата(Albun @ May 30 2012, 20:44) *
Я не сохранял регистр R12, а как оказалось компилятор этот регистр тоже использует как регистр общего назначения,

А что такое "ассемблерный код"? wink.gif.
RabidRabbit
А оно там при -O0 переменные само не инициализирует?
KnightIgor
Цитата(RabidRabbit @ May 31 2012, 12:39) *
А оно там при -O0 переменные само не инициализирует?

В коде я не полагаюсь на значения НЕинициализированных переменных, и напротив - инициализирую их, если необходимо. Не думаю, что компилятор "забывает" предписаную мной инициализацию на высоких уровнях оптимизации.

Как уже говорилось, ошибка (которую я уже и не могу "восстановить") была частой, но не регулярной, чтобы можно было бы ее стабильно репродуцировать и отследить.
vlad_new
Цитата
Вот так объявляете:
Код
void Func()
{
static char mas[100];
// код
}

Да.
Цитата
Или ОЗУ не хватит.

Странный вопрос. Вы имели ввиду что стек - та же ОЗУ. Типа если не хватит того, то и не хватит другого?
Цитата
Зря...

Зря не зря, но проблеммы с оптимизатором действительно исчезли. Да и указатели компелятор все равно создаст.
Такая уж система команд у ARM. Нет у него прямого чтения/записи только косвенные.
Так что код получается одинаковый с указателем или без.
Цитата
А оно там при -O0 переменные само не инициализирует?

Если галка стоит использования микролиб (use microLib), то все будет инициализироваться должным образом.
И к (-O0) оптимизации это не имеет оношения.
Цитата
В коде я не полагаюсь на значения НЕинициализированных переменных, и напротив - инициализирую их, если необходимо.

Я раньше тоже так делал. А сейчас сразу задаю значение при объявлении. У KEIL-а с этим все нормалек. Тут ведь просто вопрос доверия компелятору.
_Артём_
Цитата(vlad_new @ May 31 2012, 15:20) *
Да.
Странный вопрос. Если вы имели ввиду что стек - та же ОЗУ. Типа если не хватит того, то и не хватит другого?

Нет. Я о другом:
создавая массив
static unsigned char mas[100]
вы создаёте массив который существует всегда, по сути глобальный объект, но называется он - локальная статическая переменная, но память под него ушла.

Цитата(vlad_new @ May 31 2012, 15:20) *
Зря не зря, но проблеммы с оптимизатором действительно исчезли.

В этот раз повезло.

Цитата(vlad_new @ May 31 2012, 15:20) *
Да и указатели компелятор все равно создаст.
Так что код получается одинаковый с указателем или без.

Вы ещё и какие-то указатели создаёте? Зачем?
Раз компилятор "все равно создаст", то давайте их продублируем.

Цитата(vlad_new @ May 31 2012, 15:20) *
Такая уж система команд у ARM. Нет у него прямого чтения/записи только косвенные.
Так что код получается одинаковый с указателем или без.

Система команд у АРМ не той системы наверное. Понятно.
vlad_new
Цитата
Нет. Я о другом:
создавая массив static unsigned char mas[100] вы создаёте массив который существует всегда

Ну да. А мне не все равно, если памяти и скорости хватает. Зато не надо потом целый день в отладчике сидеть и искать где оптимизатор опять что то натворил.
Цитата
Вы ещё и какие-то указатели создаёте? Зачем?
Раз компилятор "все равно создаст", то давайте их продублируем.

Самое сиешное, что вы абсолютно правы. И все таки разница есть. При оптимизации компилятор руководствуется константными значениями и может натворить что угодно, а если мы явно объявили указатель на массив, то вот хрен ему. Массив он уже не тронит. К тому же в больших проэктах, а тем более
с чужими модулями и библиотеками, с указателями на массивы действительно удобнее работать. Ну опять же сколько нас - столько и мнений.

_Артём_
Цитата(vlad_new @ May 31 2012, 16:02) *
Ну да. А мне не все равно, если памяти и скорости хватает. Зато не надо потом целый день в отладчике сидеть и искать где оптимизатор опять что то натворил.

Ну если памяти хватает...

Но что там оптимизатор может натворить?
Кейл такая глючная вещь?

KnightIgor
Цитата(vlad_new @ May 31 2012, 15:02) *
Ну да. А мне не все равно, если памяти и скорости хватает.

И все же, а как быть с реентерабельностью (вложенными вызовами функций)?
vlad_new
Цитата
Но что там оптимизатор может натворить?

А Вы его и спросите. К примеру sprintf(mas,"бла...бла", tmp); при объявленном локальном массиве char mas[10] и включенном оптимизаторе O1 просто не заработал. И передача адреса массива в другую функцию send(char *mas) то же не работало. Помог static.
_Артём_
Цитата(vlad_new @ May 31 2012, 16:41) *
А Вы его и спросите.

Спросишь его ... он же памятник...

Цитата(vlad_new @ May 31 2012, 16:41) *
К примеру sprintf(mas,"бла...бла", tmp); при объявленном локальном массиве char mas[10] и включенном оптимизаторе O1 просто не заработал. И передача адреса массива в другую функцию send(mas) то же не работало.

Ужасы какие-то...
Вообще оптимизацией не воспользуешься, если оно так.
Не верю: проблема где-то в другом месте.
vlad_new
Цитата
Вообще оптимизацией не воспользуешься, если оно так.

Да, но в KEIL-е без оптимизаиора нельзя. Как тут кто то сказал: "Без оптимизатора в KEIL-е на окно дизассемблера без слез не взглянеш."
Да и скрость сразу в 2 раза ниже.
Цитата
Не верю: проблема где-то в другом месте.

А мне какой прок придумывать? Мне KEIL всеравно нравится.
_Артём_
Цитата(vlad_new @ May 31 2012, 16:59) *
Да, но в KEIL-е без оптимизаиора нельзя. Как тут кто то сказал: "Без оптимизатора в KEIL-е на окно дизассемблера без слез не взглянеш."
Да и скрость сразу в 2 раза ниже.

На то она и оптимизация чтобы быстрей работать.

Цитата(vlad_new @ May 31 2012, 16:59) *
А мне какой прок придумывать?

Я не говорю что придумываете.

Цитата(vlad_new @ May 31 2012, 16:59) *
Мне KEIL всеравно нравится.

Всё равно его не брошу потому что он хороший...
Чем может нравиться при таких косяках?
aaarrr
Цитата(vlad_new @ May 31 2012, 17:41) *
А Вы его и спросите. К примеру sprintf(mas,"бла...бла", tmp); при объявленном локальном массиве char mas[10] и включенном оптимизаторе O1 просто не заработал. И передача адреса массива в другую функцию send(char *mas) то же не работало. Помог static.

А почему у меня все работает на любых уровнях, интересно?
KnightIgor
Цитата(vlad_new @ May 31 2012, 15:41) *
А Вы его и спросите. К примеру sprintf(mas,"бла...бла", tmp); при объявленном локальном массиве char mas[10] и включенном оптимизаторе O1 просто не заработал. И передача адреса массива в другую функцию send(char *mas) то же не работало. Помог static.

А может это самое "бла...бла" было такое длиное, что не влезало в 10 байт? А когда разместилось как static, может sprintf и залезало на верхнего соседа массива, но тот был того же толка, - временная переменная (что заявленый стиль программирования позволяет предположить), - которая стерпела вторжение. Даже с пониманием того, что компилятор не безгрешен по определению, следовало бы поискать ошибки сначала у себя, прежде чем бросаться в крайности. Конечно, каждый пишет, как хочет, и окончательным критерием истины является только одно - работает программа как надо, или нет, - но я бы позволил себе дать дружеский совет пересмотреть стиль программирования.
_Артём_
Цитата(aaarrr @ May 31 2012, 17:11) *
А почему у меня все работает на любых уровнях, интересно?

Ну понятно почему: что-то не так делаете. Неправильно их готовите...
vlad_new
На счет ошибок - я уже показывал этот пример другим. Никто ошибок не обнаружил. Так что вряд ли. Хотя опять же такое было в ранних версиях.
За это время и библиотеки могли поминяться и и еще что то. У меня щас времени нет перепроверять. Хочеш сам попробуй. А потом сообщиш о результатах.


Цитата(KnightIgor @ May 31 2012, 18:16) *
А может это самое "бла...бла" было такое длиное, что не влезало в 10 байт?

Ну не 10 может 20 яж так к примеру. То что 32 бита занимают 10 символов+0+(возможно)знак я вроде как считать умею.
Мы здесь чего обсуждаем то? Разве не то кто с какими проблеммами сталкивался при оптимизации?
И от ошибок никто не застрахован. Все может быть.

Короче я все рассказал что вспомнил. Всем пока.
zuy
Цитата(vlad_new @ May 31 2012, 05:41) *
А Вы его и спросите. К примеру sprintf(mas,"бла...бла", tmp); при объявленном локальном массиве char mas[10] и включенном оптимизаторе O1 просто не заработал. И передача адреса массива в другую функцию send(char *mas) то же не работало. Помог static.


Уверен, что косяк у вас в коде. Довольно часто использовал подобные конструкции на разных уровнях оптимизации, никогда проблем не было.
Думаю, что обьяснение данное выше KnightIgor довольно точно описывает причину происходящего.
Lotor
Цитата(zuy @ Jun 1 2012, 09:58) *
Уверен, что косяк у вас в коде.

С Кейлом знаком еще по 51 семейству, еще тогда были проблемы с локальными переменными, если их передавать в функции (при чем в свои, а не в sprintf) и не обозвать static. Для arm аналогично, будет время покопаю этот момент.
aaarrr
Цитата(Lotor @ Jun 1 2012, 16:32) *
С Кейлом знаком еще по 51 семейству...

А ничего так, что это два совершенно разных компилятора от разных производителей?

99.9% "ошибок компилятора" и "багов оптимизатора" - это косяки в коде. Обратному можно верить только при наличии примера в виде код + дизассемблер.
Lotor
Цитата(aaarrr @ Jun 1 2012, 16:39) *
А ничего так, что это два совершенно разных компилятора от разных производителей?

Я это к тому, что еще с тех пор взял за правило ставить static у локальных переменных в функциях, если они идут дальше.
Цитата(aaarrr)
99.9% "ошибок компилятора" и "багов оптимизатора" - это косяки в коде. Обратному можно верить только при наличии примера в виде код + дизассемблер.

Я к этому мнению пришел недавно, намного позже, чем стал ставить static у локальных переменных. =) Поэтому и хочу при наличии времени поиграться именно с дизассемблером.
_Артём_
Цитата(Lotor @ Jun 1 2012, 15:42) *
ставить static у локальных переменных в функциях

Очень странная идея.
Зачем оно надо?

P.S. volatile не пробовали для локальных? Это хоть не так нелогично.
scifi
Цитата(_Артём_ @ Jun 1 2012, 17:31) *
P.S. volatile не пробовали для локальных? Это хоть не так нелогично.

Это танцы с бубном. Так не интересно. Лучше докопаться до сути проблемы.
Lotor
Цитата(_Артём_ @ Jun 1 2012, 17:31) *
Очень странная идея.
Зачем оно надо?

P.S. volatile не пробовали для локальных? Это хоть не так нелогично.

Вы заблуждаетесь, логика присутствует. sm.gif
При static локальная переменная будет жить в глобальной области памяти, а не на стеке. И именно поэтому проблемы исчезали.

PS: На работе попробовал по памяти набросать код, который вызывал когда-то проблемы (чтобы осмысленно глянуть в дизассемблер) - в функции локальный массив или указатель передается дальше. Но увы, всё работает, как надо при любой оптимизации. =) Помню, когда в последний раз такое случалось, я перенес аналогичный код в iar'овский компилятор - там без static работало. И т.к. это был не первый случай, то старался больше не рисковать и ставил static у локальных указателей и массивов, если они идут дальше (реентерабельность не требовалась). Прочитав эту тему по диагонали и заметив знакомую проблему, удивился что уважаемый aaarrr очень уверенно говорит, что дело не в компиляторе. Может оно и так, но помимо меня как минимум еще двое испытывают похожие проблемы.
_Артём_
Цитата(Lotor @ Jun 2 2012, 21:36) *
Вы заблуждаетесь, логика присутствует. sm.gif


Ну какая-то логика конечно присутствует, если программа всё-таки работает.


Цитата(Lotor @ Jun 2 2012, 21:36) *
При static локальная переменная будет жить в глобальной области памяти, а не на стеке. И именно поэтому проблемы исчезали.

Зачем переменной "жить в глобальной области памяти"? Локальная переменная должна жить в стеке (за исключением особых случаев).
Вопрос в том, почему такие проблемы вообще возникают. Что-то делаете не так.
Согласен с мнением scifi

Цитата
Это танцы с бубном. Так не интересно. Лучше докопаться до сути проблемы.


Каким-то образом вам удалось заткнуть проблему (с помощью static), но не факт что не вылезет где-нибудь в другом месте.

Цитата(Lotor @ Jun 2 2012, 21:36) *
И т.к. это был не первый случай, то старался больше не рисковать и ставил static у локальных указателей и массивов, если они идут дальше (реентерабельность не требовалась).


Если реентерабельность не требуется, то как бы и ладно, если по другому никак.
А как потребуется?
Или как такое будет работать в программе с ОС? Понятно что никак не будет.

Цитата(Lotor @ Jun 2 2012, 21:36) *
Прочитав эту тему по диагонали и заметив знакомую проблему, удивился что уважаемый aaarrr очень уверенно говорит, что дело не в компиляторе. Может оно и так, но помимо меня как минимум еще двое испытывают похожие проблемы.


aaarrr видимо прав на 100 %. Если у него таких проблем не возникает, то что-то эти "ещё двое" делают не правильно и дело не в компиляторе. Вообще за последние несколько лет не встречал чтобы дело было в компиляторе (правда я с iar работаю), 99% что виноват программист, ну и может доли процента можно оставить на глюки компилятора.
Lotor
Цитата(_Артём_ @ Jun 2 2012, 23:53) *
Зачем переменной "жить в глобальной области памяти"? Локальная переменная должна жить в стеке (за исключением особых случаев).

Речь шла о том, что помогло решить проблему и что дает static у локальных переменных. Другое дело, что это костыль.

Цитата(_Артём_ @ Jun 2 2012, 23:53) *
Вообще за последние несколько лет не встречал чтобы дело было в компиляторе (правда я с iar работаю), 99% что виноват программист, ну и может доли процента можно оставить на глюки компилятора.

Так вроде мы и не из этих, которые свои косяки валят на компилятор, кристалл или фазу луны. sm.gif Увы, воспроизвести "по заказу" не могу, поэтому добавляю тему в закладки - и как только, так сразу.
aaarrr
Чтобы поддержать тему, расскажу о реальном замеченном глюке оптимизации:
Компилятор игнорировал #pragma arm section при автоинлайне. То есть встраивал функцию, для которой была определена конкретная секция, в тело другой, расположенной по умолчанию.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.