Перейти к содержанию
    

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

Имеется 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-ти битными данными?

Как это побороть?

И почему не работает вышеприведенный пример?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

параметр __delay_cycles есть unsigned long!

Точно?

А может всё-таки uint?

Как это побороть?

И почему не работает вышеприведенный пример?

Я бы попробовал для начала явное приведение типа, типа:

#define Wait(mks) __delay_cycles((unsigned long)(mks*CLOCK))

 

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

Я бы не рискнул.

Изменено пользователем MrYuran

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Исходник (кусок):

 

#define QUARTZ 10000000UL

#define CLOCK QUARTZ/1000000

#define Wait(mks) __delay_cycles(mks*CLOCK)

 

Wait(480);

 

Добавьте UL

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всегда делаю так:

#define OS_FSYS_MHZ 7.3728 // Системная частота [MHz]

#define DelayUs(us) __delay_cycles((u32)((us) * OS_FSYS_MHZ))

 

да, u32 - это unsigned long

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По умолчанию (без явного объявления) к переменным и константам применяется тип 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);

даст только лишь удобство написания, но скорость вычисления не уменьшит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы ошибаетесь. Ведь это так легко проверить. ;)

А результат операции y=LINE(x); будет зависеть от типа y...

Кроме того вот так: y=LINE(2.71828) увеличит и значительно ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы ошибаетесь. Ведь это так легко проверить. ;)
Неудачный пример. Согласен :) Только подставить константы в выражение должен любой препроцессор, а вот вычислить константное выражение и подставить его значение - нет. Это уже задача оптимизации компилятора.

Кроме того вот так: y=LINE(2.71828) увеличит и значительно ;)
Увеличит? :07: Вы наверное хотели написать "уменьшит"? Потому, что такой оператор должен сводиться к банальной загрузке константы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добавьте 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:

Причём значения до 420 * CLOCKS обсчитываются правильно, а чуть побольше и пошла бредятина...

 

Всё, разобрался.

Оказывается эта, извиняюсь за выражение, "тупая скотина" в лице препроцессора или компилятора не вычисляет значение CLOCK, а просто тупо подставляет строку в нужное место.

Например, вышеприведённое выражение принимает вид:

volatile unsigned long    a    =    480 * QUARTZ / CLOCKS

а потом уже компилятор пыжится посчитать:

volatile unsigned long    a    =    480 * 10000000 / 1000000

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

 

Пришлось поставить скобки, теперь вроде всё нормально:

#define    QUARTZ    10000000UL            //Crystal quartz frequency
#define    CLOCKS    (QUARTZ/1000000)    //tacts in microsecond
#define    Wait(mksec)    __delay_cycles(mksec*CLOCKS)

    Wait(480);

 

На первый взгляд, какого чёрта делают скобки в таком простом выражении?

Ну вот откуда знаешь поначалу такие неявные мелочи?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

#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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если предположить, что вместо CLOCKS (как бы 10) препроцессор подставляет QUARTZ/1000000UL?

Что получается?

Правильно,

volatile unsigned long a = 480 * QUARTZ/1000000UL;

Теперь попробуем умножить 480 на 10000000UL...

так... умножаем... опа! 0х11E1A3000

А теперь считаем количество разрядов...

Идея понятна?

 

Спасибо за помощь, я уже сам допёр :)

 

ЗЫ: хороший форум, всегда помогут добрые люди! :a14:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 rezident

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

не вычисляет значение CLOCK, а просто тупо подставляет строку в нужное место.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мне тут ещё в голову пришло...

Всегда думал : по кой в дефайнах скобочки ставить?

А вот ведь... наглядный пример!

#define CLOCKS (QUARTZ/1000000UL)

вроде то же самое, а на самом деле - одним глюком меньше

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...