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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Вызов «xcat(xcat(1, 2), 3)» будет заменён на «123», не хватает мозга понять!
ViKo
сообщение Apr 7 2018, 19:41
Сообщение #1


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Что в книге Кернигана с Ричи, что на просторах интернет говорится о том что во вложенных макросах надо объединять строки в два этапа:
#define cat(x,y) x##y
#define xcat(x,y) cat(x,y)
и тогда уже будет нормально выполняться
xcat(xcat(1,2),3)
Как пройти по шагам, что при этом будет выполняться?
В Википедии бред какой-то наблюдаю. Также и во многих интернетных статьях.
https://ru.wikipedia.org/wiki/%D0%9F%D1%80%...80_%D0%A1%D0%B8
http://we.easyelectronics.ru/Soft/preprocessor-c.html
https://www.opennet.ru/docs/RUS/cpp/cpp-5.html
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 7 2018, 19:47
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(ViKo @ Apr 7 2018, 22:41) *
Как пройти по шагам, что при этом будет выполняться?

В свойствах проекта IAR, например, есть чекбокс "Preprocessor output to file".
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 7 2018, 19:52
Сообщение #3


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(jcxz @ Apr 7 2018, 22:47) *
В свойствах проекта IAR, например, есть чекбокс "Preprocessor output to file".

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

P.S. и стандарт листал, и все равно не понял
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 7 2018, 20:01
Сообщение #4


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Eclipse показывает 4 шага:

Код
xcat(cat(1,2),3)
xcat(12,3)
cat(12,3)
123


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 7 2018, 20:18
Сообщение #5


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



То есть, сначала в аргументе макрофункции произошла подстановка и выполнение... Почему?
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 8 2018, 05:19
Сообщение #6


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Точнее, вопрос, почему в макрофункции
cat(cat(1,2),3)
не складываются так
cat(12,3)
123
Go to the top of the page
 
+Quote Post
SSerge
сообщение Apr 8 2018, 10:31
Сообщение #7


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(ViKo @ Apr 8 2018, 12:19) *
Точнее, вопрос, почему в макрофункции
cat(cat(1,2),3)
не складываются так
cat(12,3)
123

Из вики:
Цитата
Если в замещающей последовательности перед параметром не стоит знак #, если и ни перед ним, ни после него нет знака ##, то лексемы аргумента проверяются на наличие в них макровызовов; если таковые есть, то до подстановки аргумента в нём выполняется раскрытие соответствующих макросов.

В определении cat есть ##, поэтому в аргументах раскрытие макросов не производится, они вставляются на место формальных параметров как есть (в отличие от xcat, где ни #, ни ## нет).
Получается первый аргумент - cat(1,2) и к нему присоединяется второй - 3

После подстановки к получившемуся тексту снова пытаются применить имеющийся набор макроопределений, но исключив из него уже применявшиеся (для предотвращения бесконечной рекурсии).
Определение cat как раз исключено и поэтому в получившемся тексте cat(1,2) не будет раскрываться.

В итоге получится: cat(1,2)3


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 8 2018, 10:33
Сообщение #8


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(ViKo @ Apr 8 2018, 10:19) *
Точнее, вопрос, почему в макрофункции
cat(cat(1,2),3)
не складываются так
cat(12,3)
123

Вот объяснение (отсюда):

Цитата
3.10.6 Argument Prescan

Цитата
Macro arguments are completely macro-expanded before they are substituted into a macro body, unless they are stringified or pasted with other tokens. After substitution, the entire macro body, including the substituted arguments, is scanned again for macros to be expanded. The result is that the arguments are scanned twice to expand macro calls in them.


При раскрытии xcat(xcat(1, 2), 3) сначала, как полагается, производится прескан аргументов. Раскрывается первый аргумент:
xcat(1, 2) -> cat(1, 2) -> 12.
Прескан второго аргумента дает результат 3.

Теперь раскрывается сам макрос:
xcat(12, 3) -> cat(12, 3) -> 123.


Ключевая фраза "unless they are stringified".


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 9 2018, 09:40
Сообщение #9


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Ага, так в выражении:
Если в замещающей последовательности перед параметром не стоит знак #, если и ни перед ним, ни после него нет знака ##, то лексемы аргумента проверяются на наличие в них макровызовов; если таковые есть, то до подстановки аргумента в нём выполняется раскрытие соответствующих макросов.
"если таковые есть" относится к макровызовам, а не к знакам # и ##

Так вижу правило макроподстановок касательно стрингизации и склеивания:
Если в замещающем выражении макроопределения перед параметром нет знака # или между параметрами нет знака ##, то лексемы параметров проверяются на наличие в них
макроопределений и замещаются раскрытыми макроопределениями. В противном случае параметры не проверяются на наличие в них макроопределений, а подставляются в замещающую последовательность как есть.

Рассмотрим макроподстановки xcat(xcat(1,2),3)
Видим первый внешний xcat. Смотрим, в его макроопределении (cat(x,y)) нет # или ##. Проверяем параметры xcat(1,2) и 3 этого внешнего xcat на наличие макроопределений. Находим xcat внутренний. Смотрим, в его макроопределении (cat(x,y)) нет # или ##. Проверяем его параметры 1 и 2 внутреннего xcat на наличие макроопределений. Для них макроопределений нет. Подставляем макроопределение внутреннего cat, который превращается в 12. Подставляем вместо первого параметра во внешний cat. Подставляем макроопределение внешнего cat. Получаем 123.
Go to the top of the page
 
+Quote Post
Baser
сообщение Apr 9 2018, 09:54
Сообщение #10


Просто Che
*****

Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881



Если есть желание совсем "надломить моск" smile3009.gif , можно почитать и по-разбираться по ссылкам:
C Pre-Processor Magic
C Preprocessor tricks, tips, and idioms
Я даже рискнул кое-что из этого применить в своих проектах...
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 9 2018, 10:01
Сообщение #11


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Спасибо, почитаем-с! Я, в принципе, пользуюсь макро, насколько мне нужно. И с X-macro разбирался, но не применял пока.
Вот этого нюанса с ## не знал.
Go to the top of the page
 
+Quote Post
XVR
сообщение Apr 9 2018, 11:02
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Можно проще - # и ## применяются ДО ТОГО, как производятся раскрытия макроподстановок. И только в том, что получится ПОСЛЕ # и ## ищутся и подставляются макросы.
Собственно всё sm.gif
Go to the top of the page
 
+Quote Post
Arlleex
сообщение May 4 2018, 07:50
Сообщение #13


Местный
***

Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264



В общем это тема для меня пока что не совсем понятна.
Пытаюсь сделать следующее.
Есть функция
Код
GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_SPI1);

Здесь GPIO_AF_SPI1 - это тоже некий #define.

И я хочу сделать следующее. В файле настроек иметь что-то наподобие
Цитата
#define LCD_SPI_MODULE SPI1

При этом ключевое слово SPI1 - это тоже макрос на начало области памяти модуля SPI1.

Хочу сделать так
Код
#define GPIO_AF_EXPAND_E(a, b) a##b
#define GPIO_AF_EXPAND(a, b) GPIO_AF_EXPAND_E(a, b)
GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_EXPAND(GPIO_AF_, LCD_SPI_MODULE));

Но один фиг не работает так как надо, не получаю я после разворачивания макроса GPIO_AF_SPI1 (пишет Error: L6218E: Undefined symbol GPIO_AF_ (referred from hardware.o).).

Это вообще реально? Логику макросов вообще тут понять сложно, с учетом того, что SPI1 и GPIO_AF_SPI1 - тоже макрос-объекты.

Сообщение отредактировал Arlleex - May 4 2018, 07:51
Go to the top of the page
 
+Quote Post
Baser
сообщение May 4 2018, 13:42
Сообщение #14


Просто Che
*****

Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881



Цитата(Arlleex @ May 4 2018, 10:50) *
Это вообще реально? Логику макросов вообще тут понять сложно, с учетом того, что SPI1 и GPIO_AF_SPI1 - тоже макрос-объекты.

Вы не привели законченного куска кода со всеми вложенными макросами, поэтому не совсем понятно почему вылезла именно ошибка Undefined symbol GPIO_AF_

На мой взгляд, если где-то есть описание типа:
#define SPI1 0x1234
#define LCD_SPI_MODULE SPI1
то должна быть ошибка
Undefined symbol GPIO_AF_0x1234

потому что каждый раз макросы разворачиваются до конца своей вложенности.
И можно ли на конкретном проходе макроподстановки ограничить разворачивание вложенности одним уровнем, это вопрос интересный...
Go to the top of the page
 
+Quote Post
Arlleex
сообщение May 4 2018, 16:36
Сообщение #15


Местный
***

Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264



Код
потому что каждый раз макросы разворачиваются до конца своей вложенности.

Вот. Это и есть ключ к ответу на мой вопрос laughing.gif

А насчет всех макросов, то вот:
Код
#define PERIPH_BASE 0x40000000
#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000)
#define SPI1_BASE (APB2PERIPH_BASE + 0x3000)
#define SPI1 ((SPI_TypeDef *)SPI1_BASE)

#define GPIO_AF_SPI1 ((uint8_t)0x05)

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

Код
// HW_ADCBank1Init - функция инициализации периферии для работы с внешними АЦП.
// Параметры: нет.
// Возвращаемое значение: нет.
static void HW_ADCBank1Init(void)
{
  #define LCD_SPI_MODULE SPI1
  #define GPIO_AF_EXPAND_E(a, b) a##b
  #define GPIO_AF_EXPAND(a, b) GPIO_AF_EXPAND_E(a, b)

  GPIO_PinAFConfig(GPIO_ADC_SPI1_SCK.GPIO,  GPIO_ADC_SPI1_SCK.PinSource,  GPIO_AF_EXPAND(GPIO_AF_, LCD_SPI_MODULE));
  GPIO_PinAFConfig(GPIO_ADC_SPI1_MISO.GPIO, GPIO_ADC_SPI1_MISO.PinSource, GPIO_AF_SPI1); // GPIO_AF_SPI1 я пытаюсь получить и в предыдущей строке
  ...
  ...
  ...

выдает в консоли:
Код
User\Hardware.c(449): warning:  #223-D: function "GPIO_AF_" declared implicitly

Стоит переписать как
Код
#define #define LCD_SPI_MODULE _SPI1
...
GPIO_PinAFConfig(GPIO_ADC_SPI1_SCK.GPIO,  GPIO_ADC_SPI1_SCK.PinSource,  GPIO_AF_EXPAND(GPIO_AF, LCD_SPI_MODULE));

то все работает и преобразуется во что нужно.
Однако жутко неудобен этот "хвост" в виде нижнего подчеркивания... Ведь в коде хотелось бы иметь
Код
SPI_Cmd(LCD_SPI_MODULE, ENABLE);

а не
Код
SPI_Cmd(SPI1, ENABLE);

Есть конечно решение "в лоб", это сделать несколько определений:
Код
#define LCD_SPI_MODULE SPI1
#define _LCD_SPI_MODULE_ _SPI1

и использовать первый, где требуется именно имя SPI1, а второй - там где этот кусок текста слепляется с другими макросами, например, в имени GPIO_AF_SPI1.

P.S. Уважаемые, а можно ли в тегах [код] раскрашивать текст в разный цвет? А то хотелось бы акцентировать внимание на что-то, да не получается.

Сообщение отредактировал Arlleex - May 4 2018, 16:50
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 8th July 2025 - 19:21
Рейтинг@Mail.ru


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