Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Ошибка IAR или чтото еще?
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Страницы: 1, 2
Sergio66
Столкнулся со следующей проблемой:
Использую IAR 4.20А
В программе (в функции) перемножаю два числа типа long int. Одно из них - локальная временная переменная (для упрощения расчетов). Результат умножения получается неверным (просто бред!). АВР СТУДИО показывает, что компиллятор размещает временную переменную в регистрах.
Вылечил данную проблему тем, что правдами - неправдами добился того, чтобы компиллятор разместил данную переменную в памяти. Вот только тогда все и заработало.
Кто нибудь может прокомментировать этот случай?
aesok
Показывайте код.
Sergio66
Цитата(aesok @ Dec 18 2006, 13:06) *
Показывайте код.


Вот такой код:
unsigned long int temp = INJ_time * data_temp_struct.FREQ * PRODUCTIVITY / 20000;
тип INJ_time - unsigned long int. Эта переменная локальная.
PRODUCTIVITY - константа
Так вот, переменная temp размещалась компилятором в регистрах и все было плохо

Теперь я переменную temp сделал членом локальной структуры data_temp_struct
Т.о. она стала размещаться в памяти а не в регистрах. Вот с этого все и заработало.
data_temp_struct.temp = INJ_time * data_temp_struct.FREQ * PRODUCTIVITY / 20000;
_Bill
Цитата(Sergio66 @ Dec 18 2006, 13:15) *
Вот такой код:
unsigned long int temp = INJ_time * data_temp_struct.FREQ * PRODUCTIVITY / 20000;
тип INJ_time - unsigned long int. Эта переменная локальная.
PRODUCTIVITY - константа
Так вот, переменная temp размещалась компилятором в регистрах и все было плохо

Теперь я переменную temp сделал членом локальной структуры data_temp_struct
Т.о. она стала размещаться в памяти а не в регистрах. Вот с этого все и заработало.
data_temp_struct.temp = INJ_time * data_temp_struct.FREQ * PRODUCTIVITY / 20000;

Ну, так все правильно. Компилятор перед генерацией производит свертку констант, т.е. вычисляет значение PRODUCTIVITY / 20000. Естественно, оно будет вычисленно неточно. Поставьте в выражении скобки в нужных местах. Еще советую объявить константы как long, тогда погрешность в вычислении уменьшится.
Sergio66
Цитата(_Bill @ Dec 18 2006, 14:48) *
Цитата(Sergio66 @ Dec 18 2006, 13:15) *

Вот такой код:
unsigned long int temp = INJ_time * data_temp_struct.FREQ * PRODUCTIVITY / 20000;
тип INJ_time - unsigned long int. Эта переменная локальная.
PRODUCTIVITY - константа
Так вот, переменная temp размещалась компилятором в регистрах и все было плохо

Теперь я переменную temp сделал членом локальной структуры data_temp_struct
Т.о. она стала размещаться в памяти а не в регистрах. Вот с этого все и заработало.
data_temp_struct.temp = INJ_time * data_temp_struct.FREQ * PRODUCTIVITY / 20000;

Ну, так все правильно. Компилятор перед генерацией производит свертку констант, т.е. вычисляет значение PRODUCTIVITY / 20000. Естественно, оно будет вычисленно неточно. Поставьте в выражении скобки в нужных местах. Еще советую объявить константы как long, тогда погрешность в вычислении уменьшится.


А что, если переменная размещена не в регистрах, а в памяти, свертка констант не производится? Или это происходит как то иначе?
Я ведт ничего не поменял, просто добился иного размещения в памяти переменной!!! И никаких скобок.И без них все заработало. Нет! Дело не в этом!!!
aesok
Опишите проблемму полностью:

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


Анатлий.
Dog Pawlowa
Цитата(Sergio66 @ Dec 18 2006, 15:01) *
А что, если переменная размещена не в регистрах, а в памяти, свертка констант не производится? Или это происходит как то иначе?
Я ведт ничего не поменял, просто добился иного размещения в памяти переменной!!! И никаких скобок.И без них все заработало. Нет! Дело не в этом!!!

Послушайте! :-)
Вам предлагают дело - записать формулу ПРАВИЛЬНО.
Разбираться в особенностях компилятора в случае неправильной записи - очень неблагодарное дело.
А еще можно начать разбираться в особенностях различных компиляторов. Путь в никуда.
Меня такие вещи давно не беспокоят - побольше скобок и преобразования типов.
И ффсе! smile.gif
Sergio66
Цитата(Dog Pawlowa @ Dec 18 2006, 15:28) *
Цитата(Sergio66 @ Dec 18 2006, 15:01) *

А что, если переменная размещена не в регистрах, а в памяти, свертка констант не производится? Или это происходит как то иначе?
Я ведт ничего не поменял, просто добился иного размещения в памяти переменной!!! И никаких скобок.И без них все заработало. Нет! Дело не в этом!!!

Послушайте! :-)
Вам предлагают дело - записать формулу ПРАВИЛЬНО.
Разбираться в особенностях компилятора в случае неправильной записи - очень неблагодарное дело.
А еще можно начать разбираться в особенностях различных компиляторов. Путь в никуда.
Меня такие вещи давно не беспокоят - побольше скобок и преобразования типов.
И ффсе! smile.gif

Скобки расставлял. Это ни к чему не привело. Проблема исчезла повторяю только после того, как переменная была размещена в памяти а не в регистрах!!!
prottoss
Цитата(Dog Pawlowa @ Dec 18 2006, 19:28) *
Послушайте! :-)
Вам предлагают дело - записать формулу ПРАВИЛЬНО.
Разбираться в особенностях компилятора в случае неправильной записи - очень неблагодарное дело.
А еще можно начать разбираться в особенностях различных компиляторов. Путь в никуда.
Меня такие вещи давно не беспокоят - побольше скобок и преобразования типов.
И ффсе! smile.gif
Сказанно, если размещать переменную локально, не вычисляется, если глобально - вычислятся - при чем тут скобки???
singlskv
Цитата(Sergio66 @ Dec 18 2006, 12:47) *
Столкнулся со следующей проблемой:
Использую IAR 4.20А
В программе (в функции) перемножаю два числа типа long int. Одно из них - локальная временная переменная (для упрощения расчетов). Результат умножения получается неверным (просто бред!). АВР СТУДИО показывает, что компиллятор размещает временную переменную в регистрах.
Вылечил данную проблему тем, что правдами - неправдами добился того, чтобы компиллятор разместил данную переменную в памяти. Вот только тогда все и заработало.
Кто нибудь может прокомментировать этот случай?

Если Вы смотрите на получаемое значение в окошке Watch AVR Studio, то тогда у Вас
все в порядке. Смотрите на результат в регистрах он там правильный.

AVR Studio НЕ гарантирует что локальные переменные соптимизированные компилятором
(хранящиеся в регистрах) будут правильно показываться в Watch.

А скобочки все-таки поставьте
конечно если у Вас PRODUCTIVITY / 20000 - целое, тады не надо smile.gif
Dog Pawlowa
Цитата(prottoss @ Dec 18 2006, 15:45) *
Сказанно, если размещать переменную локально, не вычисляется, если глобально - вычислятся - при чем тут скобки???

1. Было сказано так "побольше скобок И ПРЕОБРАЗОВАНИЯ ТИПОВ".
2. Ообще-тоавтор он мог бы разместить здесь ассемблерный текст и гадание на гуще не состоялось бы.
2. Видел подобный случай - я работал под IAR, клиент стал компилировать под ICC. Результат усреднения значений АЦП считался по разному. Именно из-за особенностей работы компилятора в случае некорректного написания программы. И что? И ничего.
prottoss
Цитата(Dog Pawlowa @ Dec 18 2006, 20:46) *
Цитата(prottoss @ Dec 18 2006, 15:45) *

Сказанно, если размещать переменную локально, не вычисляется, если глобально - вычислятся - при чем тут скобки???

1. Было сказано так "побольше скобок И ПРЕОБРАЗОВАНИЯ ТИПОВ".
Это было сказанно, вернее посоветованна, Вами, и товарищем aesok. Смысл же вопроса автора топика был именно в том, что сказал я - если размещать переменную локально, не вычисляется, если глобально - вычислятся , при чем здесь cкобки, позвольте? У меня, в данный момент, есть тоже подобный фокус в программе, которой сейчас занимаюсь. Если обсуждаемая сдесь проблема не решится, поделюсь своей...
Oldring
Цитата(_Bill @ Dec 18 2006, 14:48) *
Ну, так все правильно. Компилятор перед генерацией производит свертку констант, т.е. вычисляет значение PRODUCTIVITY / 20000. Естественно, оно будет вычисленно неточно. Поставьте в выражении скобки в нужных местах. Еще советую объявить константы как long, тогда погрешность в вычислении уменьшится.


Не имеет права. Ассоциативность этих операций фиксирована - слева направа.

Нужно сравнивать листинг того, как получается неправильно, и того, как получается правильно. Иначе можно много фантазировать.

Цитата(Dog Pawlowa @ Dec 18 2006, 15:28) *
Вам предлагают дело - записать формулу ПРАВИЛЬНО.


Все записано правильно.

Но нужно бы еще выяснить, какие диапазоны переменных и чему точно равны константы.
Dog Pawlowa
Цитата(prottoss @ Dec 18 2006, 17:08) *
Цитата(Dog Pawlowa @ Dec 18 2006, 20:46) *
Цитата(prottoss @ Dec 18 2006, 15:45) *

Сказанно, если размещать переменную локально, не вычисляется, если глобально - вычислятся - при чем тут скобки???

1. Было сказано так "побольше скобок И ПРЕОБРАЗОВАНИЯ ТИПОВ".
Это было сказанно, вернее посоветованна, Вами, и товарищем aesok. Смысл же вопроса автора топика был именно в том, что сказал я - если размещать переменную локально, не вычисляется, если глобально - вычислятся , при чем здесь cкобки, позвольте? У меня, в данный момент, есть тоже подобный фокус в программе, которой сейчас занимаюсь. Если обсуждаемая сдесь проблема не решится, поделюсь своей...
Видимо, Вы не поняли смысла того, что хотел сказать я. wink.gif Если есть малейшая возможность, что компилятор "спровоцирован" некорректным текстом, то лучше эту возможность исключить.

Цитата(Oldring @ Dec 18 2006, 17:27) *
Цитата(Dog Pawlowa @ Dec 18 2006, 15:28) *

Вам предлагают дело - записать формулу ПРАВИЛЬНО.

Все записано правильно.
Но нужно бы еще выяснить, какие диапазоны переменных и чему точно равны константы.
Тогда мы по разному понимает слово "правильно". Я включал в это понятие учет возможности переполнения и максимальной независимости от констант. А Вы - нет? smile.gif
Oldring
Цитата(Dog Pawlowa @ Dec 18 2006, 18:48) *
Тогда мы по разному понимает слово "правильно". Я включал в это понятие учет возможности переполнения и максимальной независимости от констант. А Вы - нет? smile.gif


Дело в том, что Билл написал просто чепуху про "естественную" свертку целочисленных констант перед вычислением выражения, а Вашего предложения я вообще почему-то не вижу в истории переписки. Так как так и не была озвучена информация про диапазоны операндов, хотелось бы все-таки увидеть, что именно Вы считаете "правильной" записью данного выражения, если это понятие "правильности" отличется от формальной правильности. Хотелось бы также узнать Ваше мнение по следующему вопросу: существует ли с точки зрения стандарта языка программирования С какая-либо разница между выражениями

Код
a * b * c / d


и

Код
((a * b) * c)  / d


?

И, кстати, считаете ли Вы что компилятор имеет право выражение

Код
a = b * 2 / 3;


заменить на

Код
a = 0;


?
singlskv
Цитата(Oldring @ Dec 18 2006, 19:08) *
Дело в том, что Билл написал просто чепуху про "естественную" свертку целочисленных констант перед вычислением выражения, а Вашего предложения я вообще почему-то не вижу в истории переписки. Так как так и не была озвучена информация про диапазоны операндов, хотелось бы все-таки увидеть, что именно Вы считаете "правильной" записью данного выражения, если это понятие "правильности" отличется от формальной правильности. Хотелось бы также узнать Ваше мнение по следующему вопросу: существует ли с точки зрения стандарта языка программирования С какая-либо разница между выражениями

Код
a * b * c / d


и

Код
((a * b) * c)  / d


?

Попробую с Вами не согласиться.
Предположим у нас есть такой код
Код
  tmp=a+153+b-35

позволим компилятору преобразовать это в
Код

tmp=a+118+b

?
или нет ?

Замечу что + и - имеет один уровень приоритета

* и / тоже один уровень
Oldring
Ответ прост. До тех пор, пока результат вычисления всего целочисленного выражения не отличается от стандартного способа вычисления с учетом того, что при переполнении промежуточных результатов возможно undefined поведение, компилятор может делать все, что угодно. Но только пока не отличается. Более того, важен даже не результат вычисления одного выражения, а последовательность записи значений в volatile переменные и вызовов системных функций. Все оптимизации программы, которые сохраняют запись в volatile переменные и ызовы системных функций - законные, все, которые приводят к изменению внешнего поведения программы - незаконны.
singlskv
Цитата(Oldring @ Dec 18 2006, 19:38) *
Ответ прост. До тех пор, пока результат вычисления всего целочисленного выражения не отличается от стандартного способа вычисления с учетом того, что при переполнении промежуточных результатов возможно undefined поведение, компилятор может делать все, что угодно. Но только пока не отличается. Более того, важен даже не результат вычисления одного выражения, а последовательность записи значений в volatile переменные и вызовов системных функций. Все оптимизации программы, которые сохраняют запись в volatile переменные и ызовы системных функций - законные, все, которые приводят к изменению внешнего поведения программы - незаконны.

Наверное все-таки так:
- если мы отключаем оптимизацию полностью
- если мы отключаем все расширения компилятора отличные от стандарта
- если мы все переменные объявляем как volatile
то тогда да, компилятор обязан сделать все как ему написали.

А вот если мы все выше перечисленное включили, то
Добро пожаловать в Manual для выяснения всех подробностей как и что
себе думает компилятор при оптимизации (если конечно авторы не забыли это указать smile.gif )
Oldring
Не совсем.

1. Включение оптимизации самой по себе не отменяет требования соблюдения компилятором стандарта языка.
2. Расширения компилятора учитывать стоит - но их обычно немного и они описаны в описании компилятора. Расширения для 8-битников могут затрагивать аривметику с 8-битными числами - не расширять до int например - но я в первый раз слышу чтобы расширения затрагивали вычисления unsigned long.
3. Нет. Компилятор обязан сделать чтобы снаружи выглядело как ему написали в любом случае.
Dog Pawlowa
Цитата(Oldring @ Dec 18 2006, 19:38) *
Ответ прост. До тех пор, пока результат вычисления всего целочисленного выражения не отличается от стандартного способа вычисления с учетом того, что при переполнении промежуточных результатов возможно undefined поведение, компилятор может делать все, что угодно. Но только пока не отличается. Более того, важен даже не результат вычисления одного выражения, а последовательность записи значений в volatile переменные и вызовов системных функций. Все оптимизации программы, которые сохраняют запись в volatile переменные и ызовы системных функций - законные, все, которые приводят к изменению внешнего поведения программы - незаконны.

Меня "правильность" компилятора мало интересует, я не д-р Туамосец.
Я рассматриваю правильность как максимально близкий результат к результату при перемножении в столбик smile.gif
И получается такая незадача, что правильность зависит от значения переменных.
int a,b,c;
a*b/c при a=100, b=100, c=3 правильно будет (a*cool.gif/c,
а при a=1000, b=1000, c=100 правильно будет a*(b/c).
Поэтому весь этот дискуссион не имеет смысла, тем более что автор не указал даже с какими числами он работал и предусмотрен ли запас по диапазону. Потому и залег на дно, видимо, предоставив нам возможность друг друга за чубы тягать smile.gif




Цитата(Oldring @ Dec 18 2006, 20:08) *
3. Нет. Компилятор обязан сделать чтобы снаружи выглядело как ему написали в любом случае.

Хм... Например, оптимизатор IAR самостоятельно заменяет switch (a) {case ....} на vector[a] и создает массив функций при большом числе a.
Такое решение выглядит, как написали, или не выглядит?
Oldring
Цитата(Dog Pawlowa @ Dec 18 2006, 20:23) *
Меня "правильность" компилятора мало интересует, я не д-р Туамосец.


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


Цитата(Dog Pawlowa @ Dec 18 2006, 20:31) *
Хм... Например, оптимизатор IAR самостоятельно заменяет switch (a) {case ....} на vector[a] и создает массив функций при большом числе a.
Такое решение выглядит, как написали, или не выглядит?


Раз такое преобразование не изменяет порядок вызова системных функций и обращений к volatile переменным - это совершенно законное преобразование программы.
prottoss
Цитата(Dog Pawlowa @ Dec 19 2006, 00:31) *
И получается такая незадача, что правильность зависит от значения переменных.
int a,b,c;
a*b/c при a=100, b=100, c=3 правильно будет (a* cool.gif /c,
а при a=1000, b=1000, c=100 правильно будет a*(b/c).
Поэтому весь этот дискуссион не имеет смысла, тем более что автор не указал даже с какими числами он работал и предусмотрен ли запас по диапазону. Потому и залег на дно, видимо, предоставив нам возможность друг друга за чубы тягать smile.gif
Вы специально со скобками дуру гоните, али как? Выражаясь Вашими формулами вопрос задаем так - ПОЧЕМУ:



Global_Value = a * b / c отличается от Local_Value = a * b / c;



Скобки и привидения к типам в обоих равенствах можете расставить по собственному усмотрению и вкусу, НО одинаково



Цитата(Dog Pawlowa @ Dec 19 2006, 00:31) *
Цитата(Oldring @ Dec 18 2006, 20:08) *

3. Нет. Компилятор обязан сделать чтобы снаружи выглядело как ему написали в любом случае.

Хм... Например, оптимизатор IAR самостоятельно заменяет switch (a) {case ....} на vector[a] и создает массив функций при большом числе a.
Такое решение выглядит, как написали, или не выглядит?
Как раз подходит под то, что говорит Oldring - снаружи функции и со switch (a) {case ....} и с vector[a] будет выглядеть одинаково, здесь же мы наблюдаем "не одинаково"
Oldring
Цитата(prottoss @ Dec 18 2006, 20:43) *
Выражаясь Вашими формулами вопрос задаем так - ПОЧЕМУ:



Global_Value = a * b / c отличается от Local_Value = a * b / c;



Скобки и привидения к типам в обоих равенствах можете расставить по собственному усмотрению и вкусу, НО одинаково


Да все что угодно может быть. Например из-за переполнения при вычислении выражения поведение оказалось неопределенным. Или результат используется каким-то специальным образом, компилятор это заметил - и соптимизировал. Листинг нужно смотреть, что там получается реально.
singlskv
Цитата(prottoss @ Dec 18 2006, 20:43) *
Выражаясь Вашими формулами вопрос задаем так - ПОЧЕМУ:

Global_Value = a * b / c отличается от Local_Value = a * b / c;

Автор топика так и не сказал, эта ошибка в "железе" или в симуляторе AVR Studio
Если в AVR Studio по Watch, то тогда надо пробовать так:
Global_Value1 = a * b / c;
Local_Value = a * b / c;
Global_Value2 = Local_Value;

и вот если не совпадут Global_Value1 и Global_Value2 то, тогда да, проблемма компиляции,
а если совпадут, то тогда все в порядке, оптимизатор поработал blink.gif
Dog Pawlowa
Цитата(prottoss @ Dec 18 2006, 20:43) *
Вы специально со скобками дуру гоните, али как? Выражаясь Вашими формулами вопрос задаем так - ПОЧЕМУ:
Global_Value = a * b / c отличается от Local_Value = a * b / c;
Скобки и привидения к типам в обоих равенствах можете расставить по собственному усмотрению и вкусу, НО одинаково

Дуру? Отчасти smile.gif
А на конкретный вопрос - конкретный ответ :

Да, сравнивать Global_Value = a * b / c и Local_Value = a * b / c при int a,b,c считаю некорректным.

Но можно сравнивать Global_Value = a * (b / c) и Local_Value = a *( b / c)
Или Global_Value = (long) a * (long) b / c и Local_Value = (long)a *(long) b / c, а еще лучше
Global_Value = ((long) a * (long) b ) / c и Local_Value = ((long)a *(long) b ) / c
И только после этого может появиться предположение об "ошибке".
У меня один и тот же проект постоянно портируется с MS VC на IAR AVR и обратно, да, было пару выбрыков у ИАРа, но в целом это вполне нормальный инструмент. За приемлемую цену wink.gif

Все, пока автор не появится - ни строчки.
Sergio66
[/quote]
Дуру? Отчасти smile.gif
А на конкретный вопрос - конкретный ответ :

Да, сравнивать Global_Value = a * b / c и Local_Value = a * b / c при int a,b,c считаю некорректным.

Но можно сравнивать Global_Value = a * (b / c) и Local_Value = a *( b / c)
Или Global_Value = (long) a * (long) b / c и Local_Value = (long)a *(long) b / c, а еще лучше
Global_Value = ((long) a * (long) b ) / c и Local_Value = ((long)a *(long) b ) / c
И только после этого может появиться предположение об "ошибке".
У меня один и тот же проект постоянно портируется с MS VC на IAR AVR и обратно, да, было пару выбрыков у ИАРа, но в целом это вполне нормальный инструмент. За приемлемую цену wink.gif

Все, пока автор не появится - ни строчки.
[/quote]

Вот и автор.
Итак, что касается значения переменных. В приведенном случае:
data_temp_struct.temp = INJ_time * data_temp_struct.FREQ * PRODUCTIVITY / 20000;
long int INJ_time = от 74 000 до 75 000
unsigned int data_temp_struct.FREQ = 1000 (задается в процессе эксперимента)
PRODUCTIVITY = 5 (в данном случае)
long int Local_Value temp = INJ_time * data_temp_struct.FREQ * PRODUCTIVITY / 20000;
где long int Local_Value размещена в регистрах
в результате дает непонятное случайное число
заменив переменную temp на data_temp_struct.temp я добился того, что она теперь размещена в памяти. При этом все вычисления пошли верно.
Теперь о свертывании констант - как вы можете видеть, PRODUCTIVITY (=5)/ 20000 корректно никак свернуто быть не может (при данных значениях)

Был проделан сл эксперимент - формула была упрощена до вида:
long int Local_Value temp = INJ_time * PRODUCTIVITY;
И только...
Результат был неверным! Только размещение в памяти результирующей переменной дало эффект!!!
Т.о. у меня есть 2 подозрения -
1. глюк компиллятора
2. Коллизия с распределением памяти. Возможно стек возвратов, возможно стек данных.
Многие глюки у меня решались именно изменением этих параметров. Правда, в данном случае мне не удалось подобрать ничего правильного.
Дело в том, что проект очень большой порядка 10 000 строк. Большой расход памяти, задействованы почти все мыслимые и немыслимые аппаратные ресурсы и прерывания.
Возможно, компиллятор столкнулся с какими то внутренними проблемами при обработке такого сложного проекта.
Кстати, оптимизацию я полностью отключал. На это грешить не приходится.

Вот такие дела!
GDI
Была у меня похожая проблема, правда, у меня портилась переменная типа char, которая была счетчиком внутри функции, при пошаговом выполнении программы в АВР-Студио выяснилось, что эта переменная размешена в регистре и при вызове вложенной подпрограммы этот регистр портился внутри этой подпрограммы, соответственно при возврате из подпрограммы мой счетчик приобретал не правильное значение.. в моем случае проблема была решена путем объявления переменной как static char, после этого она была размещена в памяти данных, а не в регистре и проблемы больше не возникало.
Oldring
Цитата(Sergio66 @ Dec 19 2006, 11:57) *
Результат был неверным! Только размещение в памяти результирующей переменной дало эффект!!!


Так сразу после вычисленя выражения в регистрах результат правильный?

Ошибки компилятора, конечно, встречаются - но в 90% случаев подозрения на ошибки компилятора не оправдываются, оказываясь ошибками программиста. Поэтому утверждение про ошибку компилятора требуют более серьезных аргументов, чем "написал так - не работает, написал иначе - работает".
Sergio66
Цитата(Oldring @ Dec 19 2006, 15:44) *
Цитата(Sergio66 @ Dec 19 2006, 11:57) *

Результат был неверным! Только размещение в памяти результирующей переменной дало эффект!!!


Так сразу после вычисленя выражения в регистрах результат правильный?

Ошибки компилятора, конечно, встречаются - но в 90% случаев подозрения на ошибки компилятора не оправдываются, оказываясь ошибками программиста. Поэтому утверждение про ошибку компилятора требуют более серьезных аргументов, чем "написал так - не работает, написал иначе - работает".


Да нет же! Пока я не переразместил переменную, все считалось неверно. И в регистрах был неверный результат.
Dog Pawlowa
Цитата(Sergio66 @ Dec 19 2006, 15:15) *
Да нет же! Пока я не переразместил переменную, все считалось неверно. И в регистрах был неверный результат.

Тот самый случай, когда лучше один раз увидеть, чем сто раз услышать.
А еще лучше совсем не видеть :-)
Я вот недавно буфер для sprintf малый сделал, и пол-дня искал причину затирания переменной, все ошибки в компиляторе искал и стек считал...
Нет? biggrin.gif
singlskv
автар
продемонстрируйте свое искуство, так сказать в "малой форме"
Напишите и выложите сюда тестовый исходник и что получаеться в дизассемблере
попробуем разобраться ...
Dog Pawlowa
Цитата(Sergio66 @ Dec 19 2006, 11:57) *
Был проделан сл эксперимент - формула была упрощена до вида:
long int Local_Value temp = INJ_time * PRODUCTIVITY;
И только...
Результат был неверным! Только размещение в памяти результирующей переменной дало эффект!!!

А говорит ANSI в этом случае? long= long * int.
Oldring
int расширяется до long до умножения. Потом должна вызываться стандартная библиотеченая функция перемножения длинных целых. Потом код самой функции должен скопировать результат из регистров в глобальную переменную. Или не скопировать. Моя уверенность, что это проблема не рассчета, а интерпретации результата, укрепляется. Пожалуй, автору пора научиться разбираться в листингах, порождаемых компилятором.
Sergio66
Цитата(Oldring @ Dec 19 2006, 19:50) *
int расширяется до long до умножения. Потом должна вызываться стандартная библиотеченая функция перемножения длинных целых. Потом код самой функции должен скопировать результат из регистров в глобальную переменную. Или не скопировать. Моя уверенность, что это проблема не рассчета, а интерпретации результата, укрепляется. Пожалуй, автору пора научиться разбираться в листингах, порождаемых компилятором.

1. Для тех кто умеет разбираться в листингах - подскажите пожалуйста, как правильно интерпретировать неправильный результат? Если в результате вычислений у меня получается неверное значение, оно же выводится на дисплей, мне придется объяснить пользователям как правильно интерпретировать такой результат который должен быть в пределах от 0,7 до 20, а его зашкаливает за 50 000!!!
2. К сожалению, я не могу выложить всеь код, т.к. это больше 10 000 строк. Одно могу сказать, что данный блок вычислений работал нормально, пока вычисления производились с глобальной переменной. Потом, для экономии памяти я сделал вычисления с локальной. Вот тут то все и началось. Когда компиллятор поместил эту локальную переменную в регистры. Как только я заставил разместить ее в памяти, все заработало.
Oldring
Цитата(Sergio66 @ Dec 20 2006, 13:33) *
1. Для тех кто умеет разбираться в листингах - подскажите пожалуйста, как правильно интерпретировать неправильный результат? Если в результате вычислений у меня получается неверное значение, оно же выводится на дисплей, мне придется объяснить пользователям как правильно интерпретировать такой результат который должен быть в пределах от 0,7 до 20, а его зашкаливает за 50 000!!!


Как какую-то Вашу собственную ошибку, например.

В настройках проекта для ICCAVR включаете на странице List опцию Output list File и отмечаете дополнительные пункты. Компилируете. В листинге находите сбойную функцию, вырезаете кусок текста и публикуете в двух вариантах. Что можно не уметь?
_Bill
Цитата(Oldring @ Dec 18 2006, 19:08) *
Цитата(Dog Pawlowa @ Dec 18 2006, 18:48) *

Тогда мы по разному понимает слово "правильно". Я включал в это понятие учет возможности переполнения и максимальной независимости от констант. А Вы - нет? smile.gif


Дело в том, что Билл написал просто чепуху про "естественную" свертку целочисленных констант перед вычислением выражения, а Вашего предложения я вообще почему-то не вижу в истории переписки. Так как так и не была озвучена информация про диапазоны операндов, хотелось бы все-таки увидеть, что именно Вы считаете "правильной" записью данного выражения, если это понятие "правильности" отличется от формальной правильности. Хотелось бы также узнать Ваше мнение по следующему вопросу: существует ли с точки зрения стандарта языка программирования С какая-либо разница между выражениями

Код
a * b * c / d


и

Код
((a * b) * c)  / d


?

И, кстати, считаете ли Вы что компилятор имеет право выражение

Код
a = b * 2 / 3;


заменить на

Код
a = 0;


?

Ну, я не думаю, что я написал чепуху. Дело в том, что операция умножения коммутативная операция, а операции умножения и деления имеют одинаковый уровень приоритета. Если взять Ваш пример, то в общем случае совершенно не важно в каком порядке производить вычисления, результат будет один и тот же. То есть
Код
b * c * d / e = (b * c * d) / e = b * c * (d / e)
Проблема возникает именно потому, что появляются типы данных. Компилятор всегда производит перегруппировку выражения таким образом, чтобы код, вычисляющий данное выражения, был минимальным. Если в выражении имеются константы, то компилятор непременно выполнит все возможные вычисления с константами в соответствии с правилами арифметики. По умолчанию все константы имеют тип int, и если их тип не указан особо, то результат также будет иметь тип int. Естественно, что результат вычисления константного выражения может быть неверным, если программист специально об этом не позаботится. В данном случае, операнды d и e будут целыми константами и компилятор обязательно вычислит результат d/e, хотя он в общем случае будет некорректным.
Если мы хотим получить корректный результат, то мы должны задать требуемый порядок вычислений явным образом с помощью скобок. Можно также изменить тип констант по умочанию с использованием соответствующих суффиксов.
Serg79
Sergio66 Ты сдесь воду то не баламуть а приведи нормальный пример своей функции которая у тебя не правельно считает. Что то типа токого:
Код
int my_bad_func(int a, int b, int c)
{
    return a * b / c;
}

А то несешь какую то ахинею типа:
Цитата
Вот такой код:
unsigned long int temp = INJ_time * data_temp_struct.FREQ * PRODUCTIVITY / 20000;
тип INJ_time - unsigned long int. Эта переменная локальная.
PRODUCTIVITY - константа
Так вот, переменная temp размещалась компилятором в регистрах и все было плохо

Теперь я переменную temp сделал членом локальной структуры data_temp_struct
Т.о. она стала размещаться в памяти а не в регистрах. Вот с этого все и заработало.
data_temp_struct.temp = INJ_time * data_temp_struct.FREQ * PRODUCTIVITY / 20000;

Если нашел ошибку то локалезуй ее. И напиши маленькую функцию которая позваляет ее воспроизвести.

А разговоры типа: в регистре не правильно а в памяти правельно, бред сивой кабылы.
Может у Тебя там полнейший бред написан, а Ты пытаешся все на компилятор свалить.
prottoss
Пока Sergio66 молчит, задам я свой вопрос, потому как проблема аналогичная. Имеем вот такой код:
Код
.....................

/* время возникновения импульса */
typedef struct
{
   UINT32 Time;  /* время возникновения импульса  */
   UCHAR TIFR_reg; /* сохраненные значения регистра флагов TIFR */

} Pulse_Time_t;
...................................

/*****************************************************************************
Коррекция значения времени
Корректирует время в зависимости от значения TIFR и младшего слова (ТС1)
******************************************************************************/
UINT32 PULSE_SENS_CorrectTime(Pulse_Time_t *Pulse)
{
UINT32 time = Pulse->Time;
  
   /* корректируем результат по состоянию флага OCF1A
    на момент считывания значений времени */
    if(Pulse->TIFR_reg & (1 << OCF1A))
    {
       time += 0x00010000; /* если флаг установлен, инкрементируем значение милисекунд */
       if(SYSTIMER_COMPARE_VAL == LOWORD(time))
        
           /* если значение счетчика равно константе в регистре сравнения, то мы это
           значение должны обнулить */
           time &= 0xffff0000;
    }

    /* преобразуем в мкс (закомментированный код НЕ РАБОТАЕТ )*/
    /* Pulse->Time = ((UINT32)(LOWORD(time) >> 1) + (UINT32)(HIWORD(time)) * 1000); return 0; */
    

    

    return ((UINT32)(LOWORD(time) >> 1) + (UINT32)(HIWORD(time)) * 1000);
}


Кто нибудь может объяснить, почему, когда я возвращаю результат преобразования в микросекунды в структуру Pulse_Time_t, результат в итоге НЕ правильный. Если возвращаю результа из функции - результат Правильный???



2 Serg79 - научитесь изъясняться по-русски, а то Ваше чревовещание больше всего подходит под термин "Бред сивой кобылы" как по грамматическим ошибкам, так и по смыслу…

Бесплатный совет – пишите сообщения сначала в
MS Word – по крайней мере, можно будет подумать, что Вы учили чего-то в школе хотя бы с соседом по парте, а свой букварь курили дома…
Oldring
Цитата(_Bill @ Dec 20 2006, 15:06) *
Код
b * c * d / e = (b * c * d) / e = b * c * (d / e)
Естественно, что результат вычисления константного выражения может быть неверным, если программист специально об этом не позаботится. В данном случае, операнды d и e будут целыми константами и компилятор обязательно вычислит результат d/e, хотя он в общем случае будет некорректным.


Чушь. Домыслы.

P.S. Хотел приложить текст стандарта - почему-то не добавился...

Цитата(prottoss @ Dec 20 2006, 16:15) *
НЕ правильный.

Бесплатный совет – пишите сообщения сначала в [/b]MS Word – по крайней мере, можно будет подумать, что Вы учили чего-то в школе хотя бы с соседом по парте, а свой букварь курили дома…


wink.gif
prottoss
Мда... Умные речи о значимости скобок не помогли...
Финал - стоны зрителей, аншлаг, занавес закрывается
Dog Pawlowa
Цитата(prottoss @ Dec 20 2006, 17:32) *
Мда... Умные речи о значимости скобок не помогли...
Финал - стоны зрителей, аншлаг, занавес закрывается

Уличили tongue.gif
А дизассемблер привести сложно? Или мы должны все бросить и посвятить вечер изучению ?
Сами то смотрели?
prottoss
Цитата(Dog Pawlowa @ Dec 20 2006, 21:54) *
А дизассемблер привести сложно? Или мы должны все бросить и посвятить вечер изучению ? Сами то смотрели?
Я смотрел, и не раз, пожалуйста, c чуйством глубокохо удовлетворения привожу листинг, смотрите:

Код
218          /*****************************************************************************
    219          Коррекция значения времени
    220          Корректирует время в зависимости от значения TIFR и младшего слова (ТС1)
    221          ***************************************************************************
***/
    222          //UINT32 PULSE_SENS_CorrectTime(Pulse_Time_t *Pulse)

   \                                 In segment CODE, align 2, keep-with-next
    223          void PULSE_SENS_CorrectTime(Pulse_Time_t *Pulse)
   \                     PULSE_SENS_CorrectTime:
    224          {
   \   00000000   2F79               MOV     R23, R25
   \   00000002   2E28               MOV     R2, R24
   \   00000004   01F8               MOVW    R31:R30, R17:R16
    225           UINT32 time = Pulse->Time;
   \   00000006   8100               LD      R16, Z
   \   00000008   8111               LDD     R17, Z+1
   \   0000000A   8122               LDD     R18, Z+2
   \   0000000C   8133               LDD     R19, Z+3
    226            
    227             /* корректируем результат по состоянию флага OCF1A
    228              на момент считывания значений времени */
    229              if(Pulse->TIFR_reg & (1 << OCF1A))
   \   0000000E   8144               LDD     R20, Z+4
   \   00000010   FF44               SBRS    R20, 4
   \   00000012   C00A               RJMP    ??PULSE_SENS_CorrectTime_0
    230              {
    231                 time += 0x00010000; /* если флаг установлен, инкрементируем значение милисекунд */
   \   00000014   5000               SUBI    R16, 0
   \   00000016   4010               SBCI    R17, 0
   \   00000018   4F2F               SBCI    R18, 255
   \   0000001A   4F3F               SBCI    R19, 255
    232                 if(SYSTIMER_COMPARE_VAL == LOWORD(time))
   \   0000001C   2F51               MOV     R21, R17
   \   0000001E   3C0F               CPI     R16, 207
   \   00000020   4057               SBCI    R21, 7
   \   00000022   F411               BRNE    ??PULSE_SENS_CorrectTime_0
    233                  
    234                     /* если значение счетчика равно константе в регистре сравнения, то мы это
    235                     значение должны обнулить */
    236                     time &= 0xffff0000;
   \   00000024   E000               LDI     R16, 0
   \   00000026   E010               LDI     R17, 0
    237              }
    238          
    239              /* преобразуем в мкс */
    240              Pulse->Time = ((UINT32)(LOWORD(time) >> 1) + (UINT32)(HIWORD(time)) * 1000);
   \                     ??PULSE_SENS_CorrectTime_0:
   \   00000028   01A8               MOVW    R21:R20, R17:R16
   \   0000002A   9556               LSR     R21
   \   0000002C   9547               ROR     R20
   \   0000002E   E060               LDI     R22, 0
   \   00000030   0189               MOVW    R17:R16, R19:R18
   \   00000032   01C8               MOVW    R25:R24, R17:R16
   \   00000034   EE08               LDI     R16, 232
   \   00000036   E013               LDI     R17, 3
   \   00000038   E020               LDI     R18, 0
   \   0000003A   E030               LDI     R19, 0
   \   0000003C   9F19               MUL     R17, R25
   \   0000003E   0D20               ADD     R18, R0
   \   00000040   1D31               ADC     R19, R1
   \   00000042   9F18               MUL     R17, R24
   \   00000044   2D10               MOV     R17, R0
   \   00000046   0D21               ADD     R18, R1
   \   00000048   1F36               ADC     R19, R22
   \   0000004A   9F09               MUL     R16, R25
   \   0000004C   0D10               ADD     R17, R0
   \   0000004E   1D21               ADC     R18, R1
   \   00000050   1F36               ADC     R19, R22
   \   00000052   9F08               MUL     R16, R24
   \   00000054   2D00               MOV     R16, R0
   \   00000056   0D11               ADD     R17, R1
   \   00000058   1F26               ADC     R18, R22
   \   0000005A   1F36               ADC     R19, R22
   \   0000005C   0F04               ADD     R16, R20
   \   0000005E   1F15               ADC     R17, R21
   \   00000060   1F26               ADC     R18, R22
   \   00000062   1F36               ADC     R19, R22
   \   00000064   8300               ST      Z, R16
   \   00000066   8311               STD     Z+1, R17
   \   00000068   8322               STD     Z+2, R18
   \   0000006A   8333               STD     Z+3, R19
    241              //return ((UINT32)(LOWORD(time) >> 1) + (UINT32)(HIWORD(time)) * 1000);
    242          }
   \   0000006C   2D82               MOV     R24, R2
   \   0000006E   2F97               MOV     R25, R23
   \   00000070   9508               RET




Что бы не напрягать попусту Ваши глаза и мозговые извилины, сделаю два замечания:

В начале кода компилятор послушно берет адрес и формирует переменную time из регистров r16-19
Код
00000000   2F79               MOV     R23, R25
   \   00000002   2E28               MOV     R2, R24
   \   00000004   01F8               MOVW    R31:R30, R17:R16
    225           UINT32 time = Pulse->Time;
   \   00000006   8100               LD      R16, Z
   \   00000008   8111               LDD     R17, Z+1
   \   0000000A   8122               LDD     R18, Z+2
   \   0000000C   8133               LDD     R19, Z+3


В конце, так же послушно запихивает то, что пережевал обратно:

Код
   \   00000064   8300               ST      Z, R16
   \   00000066   8311               STD     Z+1, R17
   \   00000068   8322               STD     Z+2, R18
   \   0000006A   8333               STD     Z+3, R19


Что и как он там насчитал, меня мало интересует, но факт остается фактом, насчитал он не правильно
Oldring
Чтобы не напрягать попусту наши извилины скомпилируйте теперь второй вариант и найдите отличия.

И, кстати, это так ведь задумано - при каждом вызове функции портить Pulse->Time?
prottoss
Цитата(Oldring @ Dec 20 2006, 22:57) *
Чтобы не напрягать попусту наши извилины скомпилируйте теперь второй вариант и найдите отличия.
И, кстати, это так ведь задумано - при каждом вызове функции портить Pulse->Time?
Именно так и задуманно, с целью сэконмить несколько десятков байт памяти программ и несколько сотен наносекунд процессорного времени. Винигрет из команд MUL, MOV, ADD, ADC абсолютно одинаковый, за исключением того, что поменены функции регистровых пар R21:20 и R25:24 в "правильно работающем варианте". Возможно ошибка в этом, а возможно еще в чем то. НО, простите, нахрена я пишу на Си, чтобы потом перелопачивать этот же код на ассемблере?

Думаю, что у Sergio66 аналогичная проблема. Возможно, это связанно именно с типом LONG... Кстати, я пользуюсь IAR v.4.10B а Sergio66 IAR v.4.20.
Oldring
Замечательно, где еще прописывается значение Pulse->Time и как часто вызывается эта функция?

И уж выложите пожалуйста "правильный" вариант.
prottoss
Цитата(Oldring @ Dec 20 2006, 23:19) *
Замечательно, где еще прописывается значение Pulse->Time и как часто вызывается эта функция?

И уж выложите пожалуйста "правильный" вариант.
А правильный вариант выложен выше в моем первом посте с исходником. "Неправильная" строчка закомментирована, и в комментариях указанна. Структура меняется в прерывании, но на момент вызова обсуждаемой функции прерывание, которое обслуживает структуру, запрещается. Структуру (их несколько) отсылает в РС основной цикл.
Oldring
Я конечно имел в виду дизассемблер, в котором изменилось распределение регистров.
singlskv
Цитата(prottoss @ Dec 20 2006, 18:05) *
Я смотрел, и не раз, пожалуйста, c чуйством глубокохо удовлетворения привожу листинг, смотрите:
Код
   \                     ??PULSE_SENS_CorrectTime_0:
   \   00000028   01A8               MOVW    R21:R20, R17:R16
   \   0000002A   9556               LSR     R21
   \   0000002C   9547               ROR     R20
   \   0000002E   E060               LDI     R22, 0
   \   00000030   0189               MOVW    R17:R16, R19:R18
   \   00000032   01C8               MOVW    R25:R24, R17:R16
   \   00000034   EE08               LDI     R16, 232
   \   00000036   E013               LDI     R17, 3
   \   00000038   E020               LDI     R18, 0
   \   0000003A   E030               LDI     R19, 0
   \   0000003C   9F19               MUL     R17, R25
   \   0000003E   0D20               ADD     R18, R0
   \   00000040   1D31               ADC     R19, R1
   \   00000042   9F18               MUL     R17, R24
   \   00000044   2D10               MOV     R17, R0
   \   00000046   0D21               ADD     R18, R1
   \   00000048   1F36               ADC     R19, R22
   \   0000004A   9F09               MUL     R16, R25
   \   0000004C   0D10                       ADD     R17, R0
   \   0000004E   1D21               ADC     R18, R1
   \   00000050   1F36               ADC     R19, R22
   \   00000052   9F08               MUL     R16, R24
   \   00000054   2D00               MOV     R16, R0
   \   00000056   0D11               ADD     R17, R1
   \   00000058   1F26               ADC     R18, R22
   \   0000005A   1F36               ADC     R19, R22
   \   0000005C   0F04               ADD     R16, R20
   \   0000005E   1F15               ADC     R17, R21
   \   00000060   1F26               ADC     R18, R22
   \   00000062   1F36               ADC     R19, R22

Prottoss
Не поленился, проверил Ваш код
сначала в голове, затем на симуляторе
Так вот: Компилятор сделал РОВНО ТО, ЧТО ВЫ У НЕГО ПОПРОСИЛИ !!!

Так что исчите апщибку в логике работы программы.

Да, кстати, присоединяюсь к
Цитата
И, кстати, это так ведь задумано - при каждом вызове функции портить Pulse->Time?

скорее всего именно здесь собака порылась
Oldring
Да, не забудьте убедиться, что функция после прерывания вызывается ровно один раз, и что прерывание действительно запрещено все время после вызова функции и до чтения результата.

Цитата(prottoss @ Dec 20 2006, 19:12) *
Думаю, что у Sergio66 аналогичная проблема.


Вероятнее всего.
prottoss
Цитата(singlskv @ Dec 20 2006, 23:29) *
Prottoss
Не поленился, проверил Ваш код
сначала в голове, затем на симуляторе
Так вот: Компилятор сделал РОВНО ТО, ЧТО ВЫ У НЕГО ПОПРОСИЛИ !!!
Так что исчите апщибку в логике работы программы.
Да, кстати, присоединяюсь к
Цитата

И, кстати, это так ведь задумано - при каждом вызове функции портить Pulse->Time?

скорее всего именно здесь собака порылась
Какая все же ошибка? Объясните не разумному?



2 Oldring - функция вызывается после того, как прерывания запрещены. После всех вычислений прерывания разрешаются.



В первом случае я возвращаю результат из функции и он правильный, во втором случае я возвращаю результат в указатель и результат, в итоге, не правильный
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.