Можно ли определить макрос внутри макроса?
Я хочу использовать параметр макроса, как это:
#define D(cond,...) do{ \
#if cond \
#define YYY 1 \
#else \
#define YYY 0 \
} while(0)
Является ли это возможным?
UPD
Может быть, когда источники будут предварительно обработаны дважды: gcc -E source.c | gcc -xc -
дальше будет работать:
#define D(cond,...) #define YYY cond&DEBUG
#if YYY
#define D(...) printf( __VA_ARGS__ )
#else
#define D(...)
#endif
6 ответов
Это невозможно. Читайте о GNU cpp
препроцессор и стандарт C11 (т.е. n1570), и проверьте здесь. Препроцессор C запускается (по крайней мере концептуально) перед остальным компилятором (который получает предварительно обработанную форму вашего модуля перевода). Кстати, для файла foo.c
вы могли бы использовать gcc -C -E foo.c > foo.i
(используя GCC), чтобы попасть внутрь foo.i
его предварительно обработанная форма, и вы можете проверить, что foo.i
Так как это текстовый файл с пейджером или редактором.
Тем не менее, .c
файл может быть сгенерирован (генерация кода C является обычной практикой, по крайней мере, с 1980-х годов; например, с yacc, bison, rpcgen, swig,....; многие крупные программные проекты используют специализированные генераторы кода C или C++...). Вы можете рассмотреть возможность использования какого-либо другого инструмента, например, препроцессора GPP (или GNU m4) или какой-либо другой программы или сценария, для создания вашего C-файла (из чего-то еще). Посмотрите также на autoconf (у него могут быть цели, похожие на ваши).
Вы можете настроить свой инструмент автоматизации сборки для таких целей, например, отредактировать свой Makefile
для GNU make
,
Нет, поскольку в C 2011 [N1570] 6.10.3.4 3 говорится о замене макросов: "Результирующая полностью замененная макросом последовательность токенов предварительной обработки не обрабатывается как директива предварительной обработки, даже если она похожа на единицу,…"
Нет, это невозможно.
Во время перевода все директивы предварительной обработки (#define
, #include
и т. д.) выполняются до того, как произойдет расширение макроса, поэтому, если макрос раскрывается в директиву предварительной обработки, он не будет интерпретироваться как таковой - он будет интерпретироваться как (неверный) исходный код.
Как отмечают другие, это невозможно, но есть обходной путь:
int YYY;
/* global scope variables are sometimes considered bad practice... */
#define D(cond,...) do{ \
if (cond) { \
YYY = 1; \
} \
else { \
YYY = 0; \
} \
} while(0)
Используйте флаг оптимизации (например: gcc/clang -O3
) и он заменит мертвый код, как если бы он был макросом. Очевидно, что вы можете изменить тип YYY, но вы, похоже, используете его как логическое значение.
Нет, ты не можешь. Препроцессор C не может знать, что произойдет во время выполнения.
Препроцессор проходит программу еще до того, как она будет скомпилирована, и заменяет каждый определенный макрос своим присвоенным значением.
Это генерация кода бедняка, ибо при интеграции в проект другого инструмента это перебор.
Определите такой макрос, расширяя его для ваших нужд:
#define NESTED /* Comment out instead of backslash new lines.
*/ /*
*/ UNDEF REPLACED /*
*/ /*
*/ IFDEF CONDITION /*
*/ DEFINE REPLACED 1 /*
*/ ELSE /*
*/ DEFINE REPLACED 0 /*
*/ ENDIF
Ваша версия может быть макросом, похожим на функцию, и
REPLACED
может иметь более развитое тело.
Оставлять
CONDITION
и директива с именем макросы без определения.
DEFINE CONDITION
контролировать, какое значение попадает при компиляции, аналогично обычному
#ifdef
Применение:
DEFINE CONDITION
NESTED
int i = REPLACED; //i == 1
UNDEF CONDITION
NESTED
int z = REPLACED; //z == 0
Исходный код, который использует и другие макросы, не будет компилироваться. Чтобы создать
.c
или же
.cpp
файл, который вы можете скомпилировать с выбранными вами параметрами, сделайте следующее:
gcc -E -CC source.c -o temporary.c
gcc -E \
-DDEFINE=\#define -DUNDEF=\#undef \
-DIFDEF=\#ifdef -DELSE=\#else -DENDIF=\#endif \
temporary.c -o usableFile.c
rm temporary.c #remove the temporary file
-E
означает только предварительную обработку, а не компиляцию. Первая команда раскрывает и все нормально определенные макросы из источника. В качестве
DEFINE
,
IFDEF
и т. д. не определены, они и их будущие аргументы остаются в файле как обычный текст.
-CC
сохраняет комментарии в выходном файле. После того, как препроцессор заменит
NESTED
своим телом,
temporary.c
содержит макросы директив в отдельных строках с комментариями. Когда комментарии удаляются для следующей команды gcc, разрывы строк остаются по стандарту.
#
принимается в теле макроса, не принимающего аргументов. Однако, в отличие от макросов, директивы не сканируются и не выполняются при расширении, поэтому вам нужен еще один проход препроцессора, чтобы заставить работать вложенные определения. Вся предварительная обработка, связанная с отложенными определениями, также должна быть отложена и сразу же доступна для препроцессора. В противном случае директивы и аргументы, необходимые для более позднего прохода, потребляются и удаляются из кода предыдущего.
Секунда
gcc
команда заменяет
-D
макросы отложенными директивами, делая их доступными для препроцессора, начиная со следующего прохода. Директивы и их аргументы не сканируются повторно в той же команде gcc и остаются буквальным текстом в файлах .
Когда вы компилируете
usableFile.c
, препроцессор выполняет отложенные директивы.