|
Вызов «xcat(xcat(1, 2), 3)» будет заменён на «123», не хватает мозга понять! |
|
|
|
Apr 8 2018, 10:31
|
Профессионал
    
Группа: Свой
Сообщений: 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.
|
|
|
|
|
Apr 8 2018, 10:33
|

фанат дивана
     
Группа: Свой
Сообщений: 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".
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 9 2018, 09:40
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 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.
|
|
|
|
|
May 4 2018, 07:50
|

Местный
  
Группа: Участник
Сообщений: 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
|
|
|
|
|
May 4 2018, 13:42
|

Просто 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 потому что каждый раз макросы разворачиваются до конца своей вложенности. И можно ли на конкретном проходе макроподстановки ограничить разворачивание вложенности одним уровнем, это вопрос интересный...
|
|
|
|
|
May 4 2018, 16:36
|

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

|
Код потому что каждый раз макросы разворачиваются до конца своей вложенности. Вот. Это и есть ключ к ответу на мой вопрос А насчет всех макросов, то вот: Код #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
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|