Не существует такого понятия, как «массив структурных литералов», независимо от того, является ли сам литерал или нет. Элементы массива могут быть структурами, и вы можете использовать структурные литералы для инициализации элементов массива структур (yuck), в том числе в литерале массива, но сами элементы массива не являются литералами. Это может звучать - действительно, может быть - педантичным, но использование непротиворечивой и правильной терминологии улучшает ясность мышления и коммуникации.
На самом деле вы вообще не используете структурные литералы или литералы массивов. Вы просто используете struct initializer внутри инициализатора для массива структур. Это уже немного упрощает проблему.
Первая проблема с вашим кодом - это круглые скобки, которые вы поместили в определение макроса CHANGE
, вокруг инициализаторов массива. Они являются частью второго аргумента для каждого вызова макроса CHANGE
, и, как таковые, они выводятся как часть замещающего текста макроса CHANGES
. Но они не являются частью разрешенного синтаксиса для инициализаторов, поэтому полученный код недействителен.
Я предполагаю, что круглые скобки стоят там во-первых, чтобы избежать запятых внутри инициализаторов, интерпретируемых как разделяющие аргументы макроса. Альтернативный способ решения этой проблемы, по крайней мере, в этом случае, состоит в том, чтобы задать определение макрокоманды CHANGE
:
#define CHANGE(change_id, ...) \
action_t current_actions ## change_id[] = __VA_ARGS__;
Это решает проблему для меня, используя стандартную форму макроса variadic, представленную в C99.
Еще одна, более структурированная альтернатива - добавить макросы для инициализаторов структуры, чтобы запятые внутри и между ними не влияли на идентификацию аргументов макроса. Например,
#define FIRST_ACTION(i,q,a) {.id=i,.quantity=q,.argument=a}
#define ACTION(i,q,a) ,FIRST_ACTION(i,q,a)
#define CHANGES \
CHANGE(1, {\
FIRST_ACTION(1,qty_None,arg_X)\
ACTION(2,qty_Many,arg_Z)\
})\
CHANGE(2, {\
FIRST_ACTION(1,qty_Some,arg_Y)\
})
// ...
#define CHANGE(change_id, actions) \
action_t current_actions ## change_id[] = actions;
CHANGES
Конечно, все это предполагает наличие некоторого хорошего значения, которое можно получить из подхода X-макроса в вашем случае. Для этого требуется как минимум другое использование макроса CHANGES
в другом месте вашего кода. Ничего такого не видно в том, что вы представляете, но это можно было бы опустить. Однако мне не сразу понятно, что ваш конкретный макрос CHANGES
предоставляет дополнительные возможности, которые не будут лучше обслуживаться другим подходом.