Пока имена переменных, которые должны быть определены, потенциально известны, тогда это может быть выполнено:
// Define a DEFINE_x macro for each x that might be enabled.
#if defined ENABLE_var1
#define DEFINE_var1 int var1;
#else
#define DEFINE_var1
#endif
#if defined ENABLE_var2
#define DEFINE_var2 int var2;
#else
#define DEFINE_var2
#endif
// Define DECLARE(x) to expand to the corresponding DEFINE_x macro.
#define DECLARE(x) DEFINE_##x
// List potential definitions.
DECLARE(var1)
DECLARE(var2)
Если имена неизвестны, то этот кладж работает:
#define Comma() ,
#define Argument3c(a, b, c,...) c
#define Argument3b(a, b,...) Argument3c(a, b, __VA_ARGS__)
#define Argument3a(a,...) Argument3b(a, __VA_ARGS__)
#define Nullify1
#define NullifyHelper(x) Nullify##x
#define Nullify(x) NullifyHelper(x)
#define DECLARE(x) Argument3a(Comma Nullify(ENABLE_##x) (), int x;,,)
DECLARE(var1)
DECLARE(var2)
Понимание этого требует более детального изучения предварительной обработки, но я приведу несколько замечаний:
- Для
-Dname
G CC определяет замену name
на 1
. Макрос Nullify
с его помощниками приводит к замене ENABLE_x
пустой последовательностью, если ENABLE_x
определено как 1
, и непустой последовательностью в противном случае. - Тогда, если в результате появилась пустая последовательность, у нас есть
Comma ()
, которая расширяется до запятой. Если это не пустая последовательность, у нас есть Comma something ()
, что не позволяет расширять функционально-подобный макрос, поэтому некоторая последовательность не включает запятую. - Через оставшиеся расширения макроса эта запятая или его отсутствие определяет, какой аргумент находится в списке аргументов, что позволяет нам выбрать либо желаемое определение, либо пустую последовательность.
Я не советую использовать это в рабочем коде. Вероятно, есть лучший способ для достижения sh вашей цели конфигурации.