Вопрос

Есть ли какой -либо способ в стандартном 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 любит насильственное обращение с препроцессором. Если они звучат так, как будто они могут помочь, вы можете узнать больше Здесь

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top