Использование препроцессорных условных выражений в макрофункциях с двойными скобками
Дано:
#define TRACE(x) do { if (DEBUG) dbg_print x; } while (0)
Я хочу:
TRACE((
"Message: %s"
#ifdef MYDEF
"Additional stuff"
#endif
, msg));
Но дает ошибку:
error C2121: '#' invalid character : possibly the result of a macro expansion
error C2146: syntax error : missing ')' before identifier 'ifdef'
error C2121: '#' invalid character : possibly the result of a macro expansion
error C2059: syntax error : ')'
Я знаю, что могу легко решить эту проблему, написав два разных вызова TRACE
и используя #ifdef...#else...#endif
, но это только упрощенный случай. Мой фактический случай использования включает в себя несколько #ifdef
, которые управляют как строкой формата, так и аргументами, поэтому не практично писать несколько вызовов трассировки (например, с 3 ifdef
, мне понадобится 2^3 = 8 различных вызовов, чтобы позаботиться обо всех возможных комбинациях). Есть ли способ обойти это? вот это?1 ответ:
Некоторые компиляторы будут компилировать ваш код через расширение компилятора, но он не является переносимым. Вы можете обойти эту проблему, условно определив другой макрос и используя его результат в вызове
TRACE
, например:#ifdef MYDEF #define IF_MY(x,y) x y #else #define IF_MY(x,y) x #endif
Теперь вы можете написать свой
TRACE
следующим образом:TRACE((IF_MY("Message: %s", "Additional stuff"), msg));
Похоже, что он столкнется с проблемами масштабируемости.
Это впечатление неверно. Вы можете легко масштабировать этот подход до такого количества переменные, как вы хотите, не сталкиваясь с комбинаторным взрывом. Вот пример добавления второй переменной:
#ifdef YOURDEF #define IF_MY_YOUR(x,y,z) IF_MY(x,y) z #else #define IF_MY_YOUR(x,y,z) IF_MY(x,y) #endif
Теперь вы можете использовать комбинированный макрос в вашем
TRACE
:TRACE((IF_MY_YOUR("Message: %s", "Additional stuff", "More stuff"), msg));
Demo #2 - оба
MYDEF
иYOURDEF
определеныDemo #2-только
YOURDEF
определеноDemo #2-только
MYDEF
определеноДемо #2-ни
MYDEF
, ниYOURDEF
не определеноЧто, если у меня есть дополнительные аргументы, которые также должны контролироваться #define?
Сделайте то же самое для параметров, с запятыми между частями
x
иy
. ВызовTRACE
будет выглядеть так:TRACE(( IF_MY_YOUR_FMT("Message: %s", "Additional %s stuff", "More %s stuff") , IF_MY_YOUR_ARG(msg1, msg2, msg3) ));