Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Макрос как параметр макроса  (Прочитано 9173 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« : 26-03-2009 08:58 » 

Есть набор структур с именами, различающимися индексом, и стоит задача выбрать одну конкретную с предопределённым индексом (т.е. индекс определён в виде подставляемого значения макроса)
Например, нужно выбрать из множества такую структуру:
Код:
struct FOO_5i {
int foo;
};

Рабочий вариант:
Код:
#define INDEX 5
#define GENERATE_NAME(prefix, value, trailing) prefix##value##trailing
#define FOO_STRUCT_INDEX(val) GENERATE_NAME(FOO_, val, i)
#define FOO_STRUCT FOO_STRUCT_INDEX(INDEX)
FOO_STRUCT test;   // test имеет тип FOO_5i

А, скажем, такой вариант не работает, подставляя не значение INDEX, а генерируя "FOO_INDEXi"
Код:
#define INDEX 5
#define GENERATE_NAME(prefix, value, trailing) prefix##value##trailing
#define FOO_STRUCT GENERATE_NAME(FOO_, INDEX, i)
FOO_STRUCT test;  // test имеет тип FOO_INDEXi, такого типа не существует
второй нерабочий вариант:
Код:
#define INDEX 5
#define GENERATE_FOO_STRUCT_NAME(value) FOO_##value##i
#define FOO_STRUCT GENERATE_FOO_STRUCT_NAME(INDEX)
FOO_STRUCT test;   // test имеет тип FOO_INDEXi, такого типа не существует

Я примерно понимаю, что происходит: судя по всему, при передаче макроса в качестве параметра другому макросу препроцессор выполняет подстановку макроса-параметра только тогда, когда разворачивает параметризованный макрос - в противном случае выполняет тупую подстановку, и конкатенация съедает макрос. Т.е. подстановка происходила бы в макросе GENERATE_NAME, но конкатенация "растворяет" макрос INDEX. Скажем, такой код
Код:
#define INDEX 5
#define GENERATE_FOO_STRUCT(value) struct FOO_##value##i { static const int foo = value; }
#define FOO_STRUCT GENERATE_FOO_STRUCT(INDEX)
FOO_STRUCT test;
порождает структуру FOO_INDEXi со статической константой, равной 5.

Суть происходящего вкратце ясна -  вопрос, насколько стандартно такое поведение. В VS2008 и MinGW поведение препроцессора одинаковое
« Последнее редактирование: 21-05-2009 03:21 от Алексей1153++ » Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #1 : 26-03-2009 11:20 » 

Эммм не совсем понял, что значит "стандартно"? -> "насколько стандартно такое поведение"
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 26-03-2009 11:30 » new

Ну, во-первых, из стандарта языка я не совсем понял, предписывается ли такая логика компилятору, или нет (мой английский недостаточно хорош для того, чтобы быстро разобраться в описании механизма подстановки аргументов макроса, а полный перевод раздела займёт некоторое время).
Если же эта логика подстановки не подпадает под стандарт, то уже просто любопытно, насколько такое решение будет кроссплатформенным.
Я подумал: вдруг кто-нибудь знает Улыбаюсь
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #3 : 26-03-2009 11:38 » 

Упс, сорри. Я чёт подраздел ANSI проморгал. Увидел С++ и на этом остановился.  А черт его знает...
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 26-03-2009 11:44 » 

Судя по примеру в стандарте:
Код:
#define glue(a, b) a ## b
#define xglue(a, b) glue(a, b)
#define HIGHLOW "hello"
#define LOW LOW ", world"

glue(HIGH, LOW); // "hello"
xglue(HIGH, LOW); // "hello" ", world" -> "hello, world" (конкатенация литеральных констант)
такое поведение, всё-таки, стандартное. Теперь ищу описание Улыбаюсь
Записан
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 26-03-2009 12:37 » 

Судя по всему, вот оно:
Цитата
16.3.1 Argument substitution
1 After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the translation unit; no other preprocessing tokens are available.
...
16.3.3 The ## operator
2 If, in the replacement list, a parameter is immediately preceded or followed by a ## preprocessing token, the parameter is replaced by the corresponding argument’s preprocessing token sequence.

То есть, должно происходить вот что:
Если у макроса есть аргументы, они подставляются куда угодно в replacement-list (то есть, в тело макроса), и перед заменой будет произведена подстановка в тех аргументах, которые содержат макро-определения.
Исключения представляют как раз случаи, когда в теле макроса аргументу предшествует # или ##, или за ним следует ##.

Следовательно, неважно, макрос там или не макрос: оператор ## игнорирует проверку при подстановке (пожалуй, точнее будет сказать, что у него своё правило подстановки: без развёртывания содержимого). А во всех остальных случаях подстановка выполняется в два этапа: 1) развёртывание макросов, входящих в аргумент; 2) собственно вставка развёрнутого аргумента куда положено в тело макроса.
« Последнее редактирование: 26-03-2009 12:41 от Вад » Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines