реклама на сайте
подробности

 
 
> Вычисление констант в процессе компиляции, Всего лишь в пределах 16 бит?
sonycman
сообщение Apr 15 2008, 12:30
Сообщение #1


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Имеется IAR 5.10 и проект на С для ATmega88.
Исходник (кусок):

#define QUARTZ 10000000
#define CLOCK QUARTZ/1000000
#define Wait(mks) __delay_cycles(mks*CLOCK)

Wait(480);

При компиляции идут предупреждения на строку с функцией о выходе значения за пределы диапазона.
Но ведь итоговое значение равно 4800, а параметр __delay_cycles есть unsigned long!
Если CLOCK жестко приравнять к 10, то все нормально.
Но если ее приравнять к 100, то получаем ту-же ошибку out of range плюс еще и о смене знака... :-(

Получается, что компилятор работает с 16-ти битными данными?
Как это побороть?
И почему не работает вышеприведенный пример?
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 12)
MrYuran
сообщение Apr 15 2008, 12:52
Сообщение #2


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(sonycman @ Apr 15 2008, 15:30) *
параметр __delay_cycles есть unsigned long!

Точно?
А может всё-таки uint?
Цитата
Как это побороть?
И почему не работает вышеприведенный пример?

Я бы попробовал для начала явное приведение типа, типа:
#define Wait(mks) __delay_cycles((unsigned long)(mks*CLOCK))

А вообще изврат по-моему, отдавать паузы на откуп компилятору...
Я бы не рискнул.

Сообщение отредактировал MrYuran - Apr 15 2008, 12:57


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
VladimirYU
сообщение Apr 15 2008, 12:56
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782



Цитата(sonycman @ Apr 15 2008, 16:30) *
Имеется IAR 5.10 и проект на С для ATmega88.
Исходник (кусок):

#define QUARTZ 10000000UL
#define CLOCK QUARTZ/1000000
#define Wait(mks) __delay_cycles(mks*CLOCK)

Wait(480);


Добавьте UL
Go to the top of the page
 
+Quote Post
YAM
сообщение Apr 15 2008, 16:39
Сообщение #4


Местный
***

Группа: Свой
Сообщений: 256
Регистрация: 7-07-04
Из: Ukraine
Пользователь №: 291



Всегда делаю так:
#define OS_FSYS_MHZ 7.3728 // Системная частота [MHz]
#define DelayUs(us) __delay_cycles((u32)((us) * OS_FSYS_MHZ))

да, u32 - это unsigned long


--------------------
Go to the top of the page
 
+Quote Post
rezident
сообщение Apr 15 2008, 16:53
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



По умолчанию (без явного объявления) к переменным и константам применяется тип int (signed int). Поскольку в стандарте Си размерность типов переменных явно не определена (определены только диапазоны в limits.h), то для надежности на 8-ми/16-и битных платформах нужно явно указывать тип больших по величине констант, добавляя к числу суффикс.
L - signed long (например, 100000L)
UL - unsigned long (например, 7372800UL)
f - float (например, 3.14159f).
Кстати, без суффикса f константа 7.3728 в примере выше
Код
#define OS_FSYS_MHZ 7.3728 // Системная частота [MHz]

может легко стать 64-и разрядной double, в зависимости от настроек проекта и/или если препроцессор посчитает это нужным. Опять же, может я конечно и ошибаюсь, но по-моему препроцессор вычисляет только целочисленные выражения в макросах. Так что макрос типа
Код
#define XMIN  1.2345
#define XMAX  2.3456
#define YMIN  3.456
#define YMAX  4.5678
#define LINE(x) ((YMAX-YMIN)/(XMAX-XMIN)*(x-XMIN)+YMIN)
при подстановке в операцию
Код
y=LINE(x);

даст только лишь удобство написания, но скорость вычисления не уменьшит.
Go to the top of the page
 
+Quote Post
YAM
сообщение Apr 15 2008, 17:00
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 256
Регистрация: 7-07-04
Из: Ukraine
Пользователь №: 291



Вы ошибаетесь. Ведь это так легко проверить. wink.gif
А результат операции y=LINE(x); будет зависеть от типа y...
Кроме того вот так: y=LINE(2.71828) увеличит и значительно wink.gif


--------------------
Go to the top of the page
 
+Quote Post
rezident
сообщение Apr 15 2008, 19:01
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(YAM @ Apr 15 2008, 23:00) *
Вы ошибаетесь. Ведь это так легко проверить. wink.gif
Неудачный пример. Согласен smile.gif Только подставить константы в выражение должен любой препроцессор, а вот вычислить константное выражение и подставить его значение - нет. Это уже задача оптимизации компилятора.
Цитата(YAM @ Apr 15 2008, 23:00) *
Кроме того вот так: y=LINE(2.71828) увеличит и значительно wink.gif
Увеличит? 07.gif Вы наверное хотели написать "уменьшит"? Потому, что такой оператор должен сводиться к банальной загрузке константы.
Go to the top of the page
 
+Quote Post
sonycman
сообщение Apr 16 2008, 06:43
Сообщение #8


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(VladimirYU @ Apr 15 2008, 17:56) *
Добавьте UL

Спасибо, добавил, ошибки исчезли, но величина задержки всё равно вычисляется неправильно.
Вот как это выглядит:

Код
#define    QUARTZ    10000000UL            //Crystal quartz frequency
#define    CLOCKS    QUARTZ/1000000UL    //tacts in microsecond

void SomeFunc(void)
{
    volatile unsigned long    a    =    480 * CLOCKS;
}


Так вот, при просмотре отладчиком полученного кода, значение а получается равным 0x0001f9, то есть 505, когда должно быть 4800...
Чёрт, что за глупости smile3046.gif
Причём значения до 420 * CLOCKS обсчитываются правильно, а чуть побольше и пошла бредятина...

Всё, разобрался.
Оказывается эта, извиняюсь за выражение, "тупая скотина" в лице препроцессора или компилятора не вычисляет значение CLOCK, а просто тупо подставляет строку в нужное место.
Например, вышеприведённое выражение принимает вид:
Код
volatile unsigned long    a    =    480 * QUARTZ / CLOCKS

а потом уже компилятор пыжится посчитать:
Код
volatile unsigned long    a    =    480 * 10000000 / 1000000

Естественно, после умножения идёт переполнение за 32 бита, и делению подлежат уже жалкие останки гигантской цифры... 07.gif

Пришлось поставить скобки, теперь вроде всё нормально:
Код
#define    QUARTZ    10000000UL            //Crystal quartz frequency
#define    CLOCKS    (QUARTZ/1000000)    //tacts in microsecond
#define    Wait(mksec)    __delay_cycles(mksec*CLOCKS)

    Wait(480);


На первый взгляд, какого чёрта делают скобки в таком простом выражении?
Ну вот откуда знаешь поначалу такие неявные мелочи?
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Apr 16 2008, 06:45
Сообщение #9


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(sonycman @ Apr 16 2008, 09:25) *
Код
#define    QUARTZ    10000000UL            //Crystal quartz frequency
#define    CLOCKS    QUARTZ/1000000UL    //tacts in microsecond

А если предположить, что вместо CLOCKS (как бы 10) препроцессор подставляет QUARTZ/1000000UL?
Что получается?
Правильно,
volatile unsigned long a = 480 * QUARTZ/1000000UL;
Теперь попробуем умножить 480 на 10000000UL...
так... умножаем... опа! 0х11E1A3000
А теперь считаем количество разрядов...
Идея понятна?

Я тут вот ещё добавлю: лучше тогда уж флот использовать, может не так точно (а надо ли), зато переполнения не будет.
Да и вообще поаккуратнее с дефайнами

Сообщение отредактировал MrYuran - Apr 16 2008, 06:48


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
sonycman
сообщение Apr 16 2008, 06:49
Сообщение #10


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(MrYuran @ Apr 16 2008, 11:45) *
А если предположить, что вместо CLOCKS (как бы 10) препроцессор подставляет QUARTZ/1000000UL?
Что получается?
Правильно,
volatile unsigned long a = 480 * QUARTZ/1000000UL;
Теперь попробуем умножить 480 на 10000000UL...
так... умножаем... опа! 0х11E1A3000
А теперь считаем количество разрядов...
Идея понятна?


Спасибо за помощь, я уже сам допёр smile.gif

ЗЫ: хороший форум, всегда помогут добрые люди! a14.gif
Go to the top of the page
 
+Quote Post
YAM
сообщение Apr 16 2008, 07:03
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 256
Регистрация: 7-07-04
Из: Ukraine
Пользователь №: 291



2 rezident
Вы писали: "даст только лишь удобство написания, но скорость вычисления не уменьшит.". Я и написал, что увеличит в плане скорости вычисления...


--------------------
Go to the top of the page
 
+Quote Post
vet
сообщение Apr 16 2008, 07:05
Сообщение #12


Знающий
****

Группа: Свой
Сообщений: 550
Регистрация: 16-06-04
Из: Казань
Пользователь №: 32



Цитата(sonycman @ Apr 16 2008, 10:43) *
не вычисляет значение CLOCK, а просто тупо подставляет строку в нужное место.

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


--------------------
Главная линия этого опуса ясна мне насквозь!
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Apr 16 2008, 07:08
Сообщение #13


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Мне тут ещё в голову пришло...
Всегда думал : по кой в дефайнах скобочки ставить?
А вот ведь... наглядный пример!
#define CLOCKS (QUARTZ/1000000UL)
вроде то же самое, а на самом деле - одним глюком меньше


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 23rd June 2025 - 07:41
Рейтинг@Mail.ru


Страница сгенерированна за 0.01481 секунд с 7
ELECTRONIX ©2004-2016