Использование препроцессорных условных выражений в макрофункциях с двойными скобками
Дано:
#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) ));