ViKo 1 7 апреля, 2018 Опубликовано 7 апреля, 2018 · Жалоба Что в книге Кернигана с Ричи, что на просторах интернет говорится о том что во вложенных макросах надо объединять строки в два этапа: #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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 7 апреля, 2018 Опубликовано 7 апреля, 2018 · Жалоба Как пройти по шагам, что при этом будет выполняться? В свойствах проекта IAR, например, есть чекбокс "Preprocessor output to file". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 7 апреля, 2018 Опубликовано 7 апреля, 2018 · Жалоба В свойствах проекта IAR, например, есть чекбокс "Preprocessor output to file". Да ну... там конечный результат будет выдан. Мне промежуточные нужны, как в Википедии показано. Но там неправильно, на мой тупой взгляд. P.S. и стандарт листал, и все равно не понял Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 7 апреля, 2018 Опубликовано 7 апреля, 2018 · Жалоба Eclipse показывает 4 шага: xcat(cat(1,2),3) xcat(12,3) cat(12,3) 123 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 7 апреля, 2018 Опубликовано 7 апреля, 2018 · Жалоба То есть, сначала в аргументе макрофункции произошла подстановка и выполнение... Почему? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 8 апреля, 2018 Опубликовано 8 апреля, 2018 · Жалоба Точнее, вопрос, почему в макрофункции cat(cat(1,2),3) не складываются так cat(12,3) 123 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SSerge 4 8 апреля, 2018 Опубликовано 8 апреля, 2018 · Жалоба Точнее, вопрос, почему в макрофункции cat(cat(1,2),3) не складываются так cat(12,3) 123 Из вики: Если в замещающей последовательности перед параметром не стоит знак #, если и ни перед ним, ни после него нет знака ##, то лексемы аргумента проверяются на наличие в них макровызовов; если таковые есть, то до подстановки аргумента в нём выполняется раскрытие соответствующих макросов. В определении cat есть ##, поэтому в аргументах раскрытие макросов не производится, они вставляются на место формальных параметров как есть (в отличие от xcat, где ни #, ни ## нет). Получается первый аргумент - cat(1,2) и к нему присоединяется второй - 3 После подстановки к получившемуся тексту снова пытаются применить имеющийся набор макроопределений, но исключив из него уже применявшиеся (для предотвращения бесконечной рекурсии). Определение cat как раз исключено и поэтому в получившемся тексте cat(1,2) не будет раскрываться. В итоге получится: cat(1,2)3 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 8 апреля, 2018 Опубликовано 8 апреля, 2018 · Жалоба Точнее, вопрос, почему в макрофункции 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". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 9 апреля, 2018 Опубликовано 9 апреля, 2018 · Жалоба Ага, так в выражении: Если в замещающей последовательности перед параметром не стоит знак #, если и ни перед ним, ни после него нет знака ##, то лексемы аргумента проверяются на наличие в них макровызовов; если таковые есть, то до подстановки аргумента в нём выполняется раскрытие соответствующих макросов. "если таковые есть" относится к макровызовам, а не к знакам # и ## Так вижу правило макроподстановок касательно стрингизации и склеивания: Если в замещающем выражении макроопределения перед параметром нет знака # или между параметрами нет знака ##, то лексемы параметров проверяются на наличие в них макроопределений и замещаются раскрытыми макроопределениями. В противном случае параметры не проверяются на наличие в них макроопределений, а подставляются в замещающую последовательность как есть. Рассмотрим макроподстановки 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. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Baser 5 9 апреля, 2018 Опубликовано 9 апреля, 2018 · Жалоба Если есть желание совсем "надломить моск" :smile3009: , можно почитать и по-разбираться по ссылкам: C Pre-Processor Magic C Preprocessor tricks, tips, and idioms Я даже рискнул кое-что из этого применить в своих проектах... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 9 апреля, 2018 Опубликовано 9 апреля, 2018 · Жалоба Спасибо, почитаем-с! Я, в принципе, пользуюсь макро, насколько мне нужно. И с X-macro разбирался, но не применял пока. Вот этого нюанса с ## не знал. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 9 апреля, 2018 Опубликовано 9 апреля, 2018 · Жалоба Можно проще - # и ## применяются ДО ТОГО, как производятся раскрытия макроподстановок. И только в том, что получится ПОСЛЕ # и ## ищутся и подставляются макросы. Собственно всё :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 4 мая, 2018 Опубликовано 4 мая, 2018 (изменено) · Жалоба В общем это тема для меня пока что не совсем понятна. Пытаюсь сделать следующее. Есть функция 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 - тоже макрос-объекты. Изменено 4 мая, 2018 пользователем Arlleex Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Baser 5 4 мая, 2018 Опубликовано 4 мая, 2018 · Жалоба Это вообще реально? Логику макросов вообще тут понять сложно, с учетом того, что SPI1 и GPIO_AF_SPI1 - тоже макрос-объекты. Вы не привели законченного куска кода со всеми вложенными макросами, поэтому не совсем понятно почему вылезла именно ошибка Undefined symbol GPIO_AF_ На мой взгляд, если где-то есть описание типа: #define SPI1 0x1234 #define LCD_SPI_MODULE SPI1 то должна быть ошибка Undefined symbol GPIO_AF_0x1234 потому что каждый раз макросы разворачиваются до конца своей вложенности. И можно ли на конкретном проходе макроподстановки ограничить разворачивание вложенности одним уровнем, это вопрос интересный... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 4 мая, 2018 Опубликовано 4 мая, 2018 (изменено) · Жалоба потому что каждый раз макросы разворачиваются до конца своей вложенности. Вот. Это и есть ключ к ответу на мой вопрос :laughing: А насчет всех макросов, то вот: #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. Уважаемые, а можно ли в тегах [код] раскрашивать текст в разный цвет? А то хотелось бы акцентировать внимание на что-то, да не получается. Изменено 4 мая, 2018 пользователем Arlleex Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться