Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: #define
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Метценгерштейн
немного не ясен момент один:

#define NUM 10
#define SUMM (NUM+8)

результат понятен.

А если поменять местами дефайны?
#define SUMM (NUM+8)
#define NUM 10

может ли препроцессор заглянуть вниз и увидеть, что NUM ниже есть у него? По описанию- не должен, но реально Keil проглатывает это.
zltigo
QUOTE (Метценгерштейн @ Jun 29 2015, 16:43) *
может ли препроцессор заглянуть вниз и увидеть, что NUM ниже есть у него? По описанию- не должен

Не должен категорически и не делает этого.
QUOTE
, но реально Keil проглатывает это.

Проглатывать и ПРАВИЛЬНО интерпретировать это разные вещи. Проглотить без предупреждения, приняв неопределнное значение за 0, может, если компилятор тупой или если
предупреждения подавлены ( обычное дело для всяких "примеров" и "библиотек" ).
CrimsonPig
Цитата(zltigo @ Jun 29 2015, 14:50) *
Не должен категорически и не делает этого.

Проглатывать и ПРАВИЛЬНО интерпретировать это разные вещи. Проглотить без предупреждения, приняв неопределнное значение за 0, может, если компилятор тупой или если
предупреждения подавлены ( обычное дело для всяких "примеров" и "библиотек" ).


Да ладно... у меня VS2010 в режиме cpp съел это без проблем и выдал правильный ответ 18
#define SUMM (NUM+8)
#define NUM 10
int aa = SUMM;

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

Вообще, ТС, завязывали бы вы с макросами, если возможно.. А то потом будете месяц искать глупую ошибку или еще хуже, эта глупая ошибка прокрадется в кхм... продакшен sm.gif из соседнего топика.
если у вас более-менее пристойный компилятор пользуйтесь константами и голова болеть не будет.

const uint32 MyNumber = 10;
const uint32 MyAnotherNumber = MyNumber+8;

inline uint32 Sum(uint32 arg) {return arg + 8;}

---
Вот вам небольшой пример макроса. Найдите в нем примерно 6 ошибок, которые приведут к неопределенному поведению вашей программы.
#define Min( A, B ) A<B ? A:B
SSerge
Цитата(Метценгерштейн @ Jun 29 2015, 20:43) *
может ли препроцессор заглянуть вниз и увидеть, что NUM ниже есть у него? По описанию- не должен, но реально Keil проглатывает это.

Препроцессору не нужно никуда заглядывать, для него директива
#define SUMM (NUM+8)
значит следующее: запомнить что если в разбираемом тексте попадётся лексема SUMM, то заменить её на текст (NUM+8).
При этом препроцессору не нужно знать что из себя представляет этот NUM, для него это просто три буквы. Только и всего. Аналогично и со вторым макроопределением.

А вот когда ниже в тексте программы попадается имя макроопределения, то производится макроподстановка, после чего получившийся текст снова разбирается от начала макроподстановки и к этому тексту снова будут применяться имеющиеся на данный момент макроопределения, за исключением уже применённых (во избежание рекурсии). Хотя вот это место даже в стандарте описано так, что ничего непонятно.

Порядок появления макроопределений в данном случае не важен, главное чтобы они оба уже встретились до того как понадобится их применение.
Метценгерштейн
Цитата(SSerge @ Jun 29 2015, 17:24) *
Препроцессору не нужно никуда заглядывать, для него директива
#define SUMM (NUM+8)
значит следующее: запомнить что если в разбираемом тексте попадётся лексема SUMM, то заменить её на текст (NUM+8).
При этом препроцессору не нужно знать что из себя представляет этот NUM, для него это просто три буквы. Только и всего. Аналогично и со вторым макроопределением.

А вот когда ниже в тексте программы попадается имя макроопределения, то производится макроподстановка, после чего получившийся текст снова разбирается от начала макроподстановки и к этому тексту снова будут применяться имеющиеся на данный момент макроопределения, за исключением уже применённых (во избежание рекурсии). Хотя вот это место даже в стандарте описано так, что ничего непонятно.

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

тогда да, все корректно понимает компилятор


#define Min( A, B ) A<B ? A:B
с этим- надо скобочки ставить, окружающие буквы, чтобы содержимое А было как единое целое.
Mihey_K
Подтверждаю: GCC 4.8 ни единого предупреждения даже с опцией -Wall, результат 18.
CrimsonPig
Цитата(Метценгерштейн @ Jun 29 2015, 15:33) *
#define Min( A, B ) A<B ? A:B
с этим- надо скобочки ставить, окружающие буквы, чтобы содержимое А было как единое целое.


Очень хорошо! sm.gif
Но чтобы выполнить задание на твердую пятерку предлагаю рассмотреть еще случай из жизни:

int i=1;
int j =2;
int k = Min(++i, ++j);

и сравнить его со следующей имплементацией:

inline int Min_Better(int a1, a2) {return (a1<a2) ? a1: a2;}
Mihey_K
А это уже некорректно: Min(++i, ++j);
Подобную запись отцы не рекомендуют, страница 57.
zltigo
QUOTE (Метценгерштейн @ Jun 29 2015, 17:33) *
с этим- надо скобочки ставить, окружающие буквы, чтобы содержимое А было как единое целое.

Без скобок - беда. Только вопрос, где их ставить - лучше привыкать ВСЕГДА АБСОЛЮТНО ВСЕГДА, АВТОМАТИЧЕСКИ НЕ ДУМАЯ, ставить их при #define этих самых A и иже с ними. Тогда не надо будет городить специально конструкции со скобками в выражениях, в которых они явно не требуются.

QUOTE (Метценгерштейн @ Jun 29 2015, 17:33) *
тогда да, все корректно понимает компилятор

Ну для начала не компилятор, а препроцессор. И все-же НЕ обязан, поскольку, увы, начинается очевидная зависимость от реализации препроцессора. Как и Min(++i, ++j) от реализации компилятора.

QUOTE (CrimsonPig @ Jun 29 2015, 17:15) *
Вообще, ТС, завязывали бы вы с макросами, если возможно..

Категорически не могу согласиться. Мысли надо выражать максимально понятно себе и компилятору. Создавать код-макроме в рассчете, что "пристойный компилятор" заоптимизирует и уберет ненужности и глупости.
Mihey_K
Цитата
начинается очевидная зависимость от реализации препроцессора

Полностью согласен, использование конструкций, неопределенных стандартом языка, чревато непереносимостью кода даже между разными версиями одного компилятора.
ViKo
Не уверен, что вопрос уже не задавался, напишу в первой подходящей теме, потому что найти не реально.
Константами какой размерности оперирует препроцессор? unsigned int? Или можно задать суффикс ULL, и будет 64-битовое представление? Конкретно интересует Keil.

Проверил на примере #define TEST (1000000000000ULL / 1000000001)
Рассчитывает правильно. (А в том, что творю, что-то ломается. Но это мои косяки.)
Mihey_K
Все правильно вы сделали, LL для long long, и эта возможность определяется стандартом, а не компилятором. Базовый тип целочисленного представления числа без модификатора равен битности платформы, т. ё. по умолчанию int. Ссылка
ViKo
Цитата(Mihey_K @ Aug 28 2015, 14:18) *
Все правильно вы сделали, LL для long long...

Спасибо. Дело было не в LL. Я уже тему создал по данному вопросу.
SSerge
Цитата(ViKo @ Aug 28 2015, 17:44) *
Проверил на примере #define TEST (1000000000000ULL / 1000000001)
Рассчитывает правильно. (А в том, что творю, что-то ломается. Но это мои косяки.)

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

Другое дело, если написать что-то вроде
#if constant_expression
тогда считать придётся уже препроцессору. Как именно он это считает должно быть описано в доке на препроцессор.
ViKo
Что же он (препроцессор), то считает, то не считает..? rolleyes.gif Считал бы уже все подряд, помог бы компилятору.
Вот тема, просветила меня.
Mihey_K
Препроцессор может считать только предопределенные значения, т.к. выполняется он до прохода компилятором, и понятия не имеет, какие входные данные ему могут быть поданы. Посему применять препроцессор есть смысл для регулярных выражений, либо для явного наименования численного значения для упрощения восприятия кода, уменьшения ошибок и облегчения сопровождения.
ViKo
Цитата(Mihey_K @ Aug 28 2015, 17:05) *
Препроцессор может считать только предопределенные значения, т.к. выполняется он до прохода компилятором, и понятия не имеет, какие входные данные ему могут быть поданы.

Так
#define TEST (1000000000000ULL / 1000000001)
предопределеннее некуда, а SSerge говорит, что не считает.
SSerge
Цитата(ViKo @ Aug 29 2015, 00:08) *
Так
#define TEST (1000000000000ULL / 1000000001)
предопределеннее некуда, а SSerge говорит, что не считает.

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

Для проверки включите выдачу результата работы препроцессора в файл, да и посмотрите что там будет.
Кейла у меня нет, могу на примере IAR-а продемонстрировать что препроцессор делает только подстановку, а вычисляет выражение уже компилятор:
Код
//файл main.cpp
void foo()
{
#define TEST (1000000000000ULL / 1000000001)
  SysTick_Config( TEST );
}

Код
//файл main.i  - выход препроцессора
void foo()
{
  SysTick_Config( (1000000000000ULL / 1000000001) );
}

Код
//файл main.lst
     76          void foo()
     77          {
     78          #define TEST (1000000000000ULL / 1000000001)
     79            SysTick_Config( TEST );
   \                     _Z3foov: (+1)
   \   00000000   0xF240 0x30E7      MOVW     R0,#+999
   \   00000004   0x....             B.N      _Z14SysTick_Configj
     80          }
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.