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

Препроцессор ведёт себя неоднозначно. Как это понять?

Вот, в одном проекте, в начале main.c стоят строчки:

#define     FCLK                16.0E6        // 16MHz

#define     FREQ_COEFF          (double)(pow(2.0,32) / FCLK)

Подразумевается, что в препроцессоре вычислится FREQ_COEFF (получается где-то 268.4), после чего это число будет использоваться в теле программы. И именно так и происходит.

А в другом, совершенно аналогичном проекте, функция pow() в препроцессоре не вычисляется, а начинает тормозить во всех тех местах, где упоминается FREQ_COEFF.

Как это? Почему так происходит?
Как отследить/настроить/победить?

Спасибо.

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


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

Препроцессор ничего вычислять не умеет, он только текст подставляет, и если компилятор умный, то догадается что FREQ_COEFF константа и посчитает её при компиляции, если не очень или уровень оптимизации невысокий, скомпилирует как попросили вызов pow.

 

#define FREQ_COEFF (4294967296.0/FCLK)

 

 

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


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

14 minutes ago, _pv said:

Препроцессор ничего вычислять не умеет, он только текст подставляет, и если компилятор умный, то догадается что FREQ_COEFF константа и посчитает её при компиляции, если не очень или уровень оптимизации невысокий, скомпилирует как попросили вызов pow.

Всё, разобрался!
Ключевое слово = УРОВЕНЬ ОПТИМИЗАЦИИ!!!
При низких уровнях препроцессор - глупый, а при максимальных - всё получается.
Огромное мерси!
:)

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


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

Чтобы не надеяться, что компилятор сам поймёт, что выражение есть константа времени компиляции, и вычислит её один раз, надо самому объявить её таковой с помощью квалификатора constexpr. От компилятора понадобится поддержка стандарта с++11.

constexpr double FCLK=16.0;      // 16 MHz

constexpr double FREQ_COEFF=pow(2.0,32)/FCLK;

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


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

14 hours ago, Alexey_N said:

Всё, разобрался!
Ключевое слово = УРОВЕНЬ ОПТИМИЗАЦИИ!!!
При низких уровнях препроцессор - глупый, а при максимальных - всё получается.

препроцессор глупый всегда.

даже без C++11 вместо дефайна можно объявить const double FREQ_COEFF=pow(2.0,32)/FCLK; тогда в худшем случае посчитает один раз, если не догадается вычислить на этапе компиляции.

но как и в случае с constexpr в заголовочный файл для включения в другие части тогда придётся написать extren const double FREQ_COEFF; а вычислить где-то один раз отдельно.

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


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

17 часов назад, Alexey_N сказал:

Ключевое слово = УРОВЕНЬ ОПТИМИЗАЦИИ!!!
При низких уровнях препроцессор - глупый, а при максимальных - всё получается.

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

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


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

3 hours ago, jcxz said:

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

Да, я прошу прощения, в суете неправильно выразился. Разумеется речь шла о компиляторе.

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


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

17 hours ago, Darth Vader said:

Чтобы не надеяться, что компилятор сам поймёт, что выражение есть константа времени компиляции, и вычислит её один раз, надо самому объявить её таковой с помощью квалификатора constexpr. От компилятора понадобится поддержка стандарта с++11.

Увы, не поддерживает :(. (Ругается, хотя и знает это слово.)
Может быть эту поддержку где-то в настройках включать надо?

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


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

5 hours ago, _pv said:

даже без C++11 вместо дефайна можно объявить const double FREQ_COEFF=pow(2.0,32)/FCLK; тогда в худшем случае посчитает один раз, если не догадается вычислить на этапе компиляции.

Так очень было бы хорошо, но вот при компиляции ругается:

Error[Pe059]: function call is not allowed in a constant expression

Что я сделал не так?

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


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

Дословный перевод: вызов функций не поддерживается в константных выражениях. Значит не судьба через constexpr. В таких выражениях имеются некоторые ограничения, зависящие от версии поддерживаемого стандарта С++:11/14/17 и особенностей компилятора. Чем новее стандарт и "продвинутей" компилятор, тем меньше в нём ограничений на средства вычисления константных выражений.

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


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

56 минут назад, Alexey_N сказал:

Error[Pe059]: function call is not allowed in a constant expression

Что я сделал не так?

Вам же компилятор английским по белому сказал: вызываете функцию. Избавьтесь от pow() и никакие c++11 не потребуются.

 

PS: Видел уже как некоторые "программисты" передают числовые аргументы в функцию переводя их в строку (а внутри - переводя обратно в число). Возведение 2 в целую степень при помощи функции pow() - этот "перл" быдлокодерства будет не хуже.

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


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

3 minutes ago, jcxz said:

Вам же компилятор английским по белому сказал: вызываете функцию. Избавьтесь от pow() и никакие c++11 не потребуются.

Это очевидно, но вот совсем избавляться от функций в предварительных расчетах как-то не охота...
Видимо должен существовать некий легальный механизм, чтобы заранее посчитать все константы в начале игры, вне зависимости от с++11.
Ну, по крайней мере, хотелось бы на это надеяться.

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


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

То есть использовать

#define FREQ_COEFF (4294967296 / FCLK)

#define FREQ_COEFF ((1 << 32) / FCLK)

нельзя ?

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


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

46 minutes ago, x893 said:

То есть использовать

#define FREQ_COEFF (4294967296 / FCLK)

#define FREQ_COEFF ((1 << 32) / FCLK)

нельзя ?

Да с калькулятором в руках можно вообще порешать большинство жизненных затруднений!
:)
Конечно, в данном простейшем примере всё так и делается. Но ведь хотелось бы решить проблему в общем случае, чтобы потом уже не возвращаться к этим непоняткам, когда вначале проекта рассчитываются константы не такие простые, да и по сложному набору функций...
Ну раз уж разговор зашел предметный, то почему бы и не дорыхлить тему до конца?

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


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

10 minutes ago, Alexey_N said:

то почему бы и не дорыхлить тему до конца?

то почему бы не взрыхлить тему до конца

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


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

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

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

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

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

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

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

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

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

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