Можно ли определить макрос внутри макроса?

Я хочу использовать параметр макроса, как это:

  #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, препроцессор выполняет отложенные директивы.

Другие вопросы по тегам