Является ли использование макросов C / C ++ в качестве ярлыка для условной компиляции хорошей практикой?

13

Допустим, я хочу, чтобы в моем коде было несколько типов выходных сообщений. Один из них DEBUG, который печатается, только когда код скомпилирован в режиме отладки.

Обычно я должен был написать что-то вроде

#ifdef DEBUG
    std::cout << "Debug message" << std::endl;
#endif

что довольно громоздко и раздражает во многих местах.

Является ли хорошей практикой определение макроса для фрагмента кода, чтобы вы использовали его таким образом?

MSG_DEBUG("Debug message")

Или есть какой-нибудь другой, более изящный способ, как справиться с этим без макросов? Меня интересуют возможные решения как на C, так и на C ++, так как я использую оба языка в разных проектах.

Eenoku
источник
Из вопроса не ясно, почему вы не просто поместили бы условный код в функцию и вызвали бы это. Есть ли какие-то другие ограничения, которые могли бы предотвратить это?
Алекс
@gnat Вопрос, который вы упомянули, настолько широк, что большинство людей не связывают его с этой темой, особенно если они будут искать этот конкретный вопрос в Интернете.
Eenoku
3
Ваш вопрос помечен как c, так и c ++ , однако это довольно разные языки. Можете ли вы уточнить, о ком вы говорите? Ваш пример будет прекрасно в C, но может быть лучше реализован с constexpr ifC ++, например.
Йорг Миттаг
1
Помимо этого, диагностика должна идти STDERR. Кроме того, почему бы не заставить его зависеть от того, NDEBUGчто assert()делает вместо этого? Затем вы можете определить его как #define DEBUG_MSG(MSG) assert(std::cerr << MSG), который также проверяет состояние потока.
Дедупликатор

Ответы:

19

Конечно, если вы в первую очередь согласны с использованием макросов, то любой параметр хорошего кодирования, безусловно, предпочтительнее определить параметризованный, а не повторять один и тот же условный код.

Вы должны использовать макросы вообще? На мой взгляд, вам следует, так как это принято в C, и любое решение без макросов потребует выполнения хотя бы чего- то даже вне режима отладки. Типичный C-программист в любой момент выберет немного уродливый макрос вместо ненужных усилий во время выполнения.

Килиан Фот
источник
13

Здесь есть элемент личных предпочтений, но в C ++ я предпочитаю делать это в заголовочном файле:

#ifdef _DEBUG
    void DebugMessage(...);
#else
    inline void DebugMessage(...) {}
#endif

Таким образом, эта функция встроена в сборку релиза, но является правильной функцией в сборке отладки, поэтому вы можете иметь надлежащую проверку типов, заметные сообщения об ошибках и т. Д., А также возможность добавлять дополнительные функции (возможно, в журнал?).

Очевидно, вам также необходимо заключить соответствующее определение функции в .cppфайл в #ifdef _DEBUGблок.

Джек Эйдли
источник
Но накладные расходы по-прежнему присутствуют здесь, не так ли?
Eenoku
7
Если ваш компилятор сгенерирует код для вызова известной пустой функции в сборке релиза, первое и самое важное, что вам нужно сделать для повышения эффективности, - это получить гораздо лучший компилятор. Это действительно тривиальная оптимизация.
Дэвид Торнли
@Eenoku Нет, как говорит Дэвид, он будет удален любым компилятором, который вы должны использовать.
Джек Эйдли
3
Здесь есть ключевое отличие: макрос (в зависимости от того, как он написан) не будет оценивать выражения аргумента, а функция всегда будет это делать. Кроме того, это ненадежное поведение - передавать нетривиальные аргументы в функции varargs (и обычно выдает предупреждения компилятора).
Себастьян Редл
2

Определенно, просто убедитесь, что вы не наступаете на правила, изложенные вашей командой. Убедитесь, что никакой другой код в системе не пытается достичь той же функциональности через общее условие if.

Джеймс О
источник