Могу ли я добавить к препроцессорному макросу?
-
13-10-2019 - |
Вопрос
Есть ли какой -либо способ в стандартном C - или с расширениями GNU - чтобы добавить материал к определению макроса? Например, учитывая макрос, определяемый как
#define List foo bar
Могу я добавить bas
так что это List
расширяется, как будто я определил это
#define List foo bar bas
?
Я надеялся сделать что -то вроде этого:
#define List foo bar bas
#define List_ Expand(List)
#undef List
#define List Expand(List_) quux
Но я не могу понять, как определить Expand()
Макро, так что он будет делать то, что я хочу.
Мотивация:Я играю с дискриминационными/помеченными профсоюзами по этим направлениям:
struct quux_foo { int x; };
struct quux_bar { char *s; };
struct quux_bas { void *p; };
enum quux_type {quux_foo, quux_bar, quux_bas};
struct quux {
enum quux_type type;
union {
struct quux_foo foo;
struct quux_bar bar;
struct quux_bas bas;
} t;
};
Я полагаю, что это хорошее место для X-Macro. Если я определю макрос
#define quux_table X(foo) X(bar) X(bas)
Перечисление и структура могут быть определены таким образом и никогда не выходить из синхронизации:
#define X(t) quux_ ## t,
enum quux_type {quux_table};
#undef X
#define X(t) struct quux_ ## t t;
struct quux {
enum quux_type type;
union {quux_table} t;
};
#undef X
Конечно, quux_*
Структуры могут выйти из синхронизации, поэтому я хотел бы сделать что -то подобное, только на законных основаниях:
struct quux_foo { int x; };
#define quux_table quux_table X(foo)
struct quux_bar { char *s; };
#define quux_table quux_table X(bar)
struct quux_bas { void *p; };
#define quux_table quux_table X(bas)
(Ну, что я В самом деле хочу сделать что -то вроде
member_struct(quux, foo) { int x; };
Но я хорошо знаю, что макросы не могут быть (повторно) из макросов).
Во всяком случае, это мой мотивирующий пример. Есть ли способ сделать это?
Примеры Boost.Preprocessor в порядке, если вы можете показать мне, как заставить технику X-Macro работать с этой библиотекой.
Решение
Фактически нет.
Макросы лениво оцениваются. Когда ты #define List_ Expand(List)
, его список замены - последовательность четырех токенов Expand
, (
, List
, а также )
. Анкет Нет никакого способа расширить макрос в список замены.
Вся замена макрос происходит, когда вызывает макрос.
Я бы порекомендовал взглянуть на использование библиотеки Boost.preprocessor для автоматического генерации кода. Это немного работы, но вы можете сделать некоторые довольно впечатляющие вещи используй это. Он должен быть полностью совместимы с C.
Другие советы
Есть выход!
Используя новое ключевое слово _pragma Это может быть достигнуто в GCC (хотя и не с MSVC)
Если вы выдвигаете макрос в своем собственном определении, он задержит его расширение, пока макрос не будет расширен в первый раз. Это позволяет вам сделать его предыдущую часть расширения своей собственной определения. Однако, поскольку он выскочен во время его расширения, его можно использовать только один раз
Вот какой -то пример кода, чтобы увидеть его в действии
#define pushfoo _Pragma("push_macro(\"foo\")") //for convenience
#define popfoo _Pragma("pop_macro(\"foo\")")
#define foo 1
pushfoo //push the old value
#undef foo //so you don't get a warning on the next line
#define foo popfoo foo , 2 //append to the previous value of foo
pushfoo
#undef foo
#define foo popfoo foo , 3
pushfoo
#undef foo
#define foo popfoo foo , 4
foo //this whole list will expand to something like popfoo foo popfoo foo popfoo foo , 4
//which will in turn expand to 1 , 2 , 3 , 4
foo //the second time this will expand to just 1
Эта опция должна облегчить генерацию автоматического кода, хотя, к сожалению, только на GCC (возможно, Clang, не протестировал)
Честно говоря, я не могу найти, почему это должно работать, это, скорее всего, неопределенное поведение работает. Я предполагаю, что причина в том, что после того, как FOO выпал, текущий макрос расширенный макрос больше не связан с именем Foo, которое позволяет символ foo
быть расширенным, но это только моя гипотеза
Редактировать:
После тестирования на Clang это не Работает над Кланг.
Я не знаю, почему я думал, что Кланг не работает, может быть, это не на другой машине. Я определенно заставил его работать с данным кодом
Я не уверен, поможет ли это, но вы можете сделать макросы Vari Arg. Г -н Конрад из проекта X264 любит насильственное обращение с препроцессором. Если они звучат так, как будто они могут помочь, вы можете узнать больше Здесь