Это может быть вопросом стиля, но в нашей команде разработчиков есть некоторые разногласия, и мне было интересно, есть ли у кого-нибудь еще какие-нибудь идеи по этому поводу ...
По сути, у нас есть некоторые отладочные операторы печати, которые мы отключаем во время нормальной разработки. Лично я предпочитаю делать следующее:
//---- SomeSourceFile.cpp ----
#define DEBUG_ENABLED (0)
...
SomeFunction()
{
int someVariable = 5;
#if(DEBUG_ENABLED)
printf("Debugging: someVariable == %d", someVariable);
#endif
}
Однако некоторые из команды предпочитают следующее:
// #define DEBUG_ENABLED
...
SomeFunction()
{
int someVariable = 5;
#ifdef DEBUG_ENABLED
printf("Debugging: someVariable == %d", someVariable);
#endif
}
... какой из этих методов вам больше подходит и почему? Я считаю, что первое безопаснее, потому что всегда есть что-то определенное и нет опасности, что это может разрушить другие определения где-то еще.
c++
c
if-statement
coding-style
c-preprocessor
Джон Кейдж
источник
источник
#if
, вы также можете использовать#elif
последовательно, в отличие от с#ifdef
. Таким образом, вместо того, чтобы просто использовать#define BLAH
, использовать#define BLAH 1
с#if BLAH
и т. Д.Ответы:
Моя первоначальная реакция
#ifdef
, конечно, была , но я думаю, что на#if
самом деле у этого есть некоторые существенные преимущества - вот почему:Во-первых, вы можете использовать
DEBUG_ENABLED
в препроцессорных и скомпилированных тестах. Пример. Часто мне нужны более длительные тайм-ауты, когда включена отладка, поэтому, используя#if
, я могу написать это... вместо того ...
Во-вторых, вы находитесь в лучшем положении, если хотите перейти от
#define
константы к глобальной.#define
Большинство программистов на C ++ обычно неодобрительно относятся к s.И, в-третьих, вы говорите, что в вашей команде раскол. Я предполагаю, что это означает, что разные участники уже приняли разные подходы, и вам нужно стандартизировать. Правило, которое
#if
является предпочтительным выбором, означает, что используемый код#ifdef
будет компилироваться и запускаться, даже если онDEBUG_ENABLED
является ложным. И гораздо проще отследить и удалить вывод отладки, который создается, когда он не должен быть, чем наоборот.Да, и еще один незначительный момент для удобочитаемости. Вы должны иметь возможность использовать true / false, а не 0/1 в вашем
#define
, и поскольку значение представляет собой один лексический токен, это единственный раз, когда вам не нужны круглые скобки вокруг него.вместо того
источник
#ifdef
том, что он работает с вещами, которые не определены; не определены ли они намеренно, из-за опечатки или чего-то еще.#if DEBUG_ENBALED
не является ошибкой, обнаруженной препроцессором. ЕслиDEBUG_ENBALED
не определен, он расширяется до токена0
в#if
директивах.Они оба ужасны. Вместо этого сделайте следующее:
Затем, когда вам понадобится отладочный код, вставьте его внутрь
D();
. И ваша программа не засорена отвратительными лабиринтами#ifdef
.источник
#ifdef
просто проверяет, определен ли токен, учитываязатем
источник
У нас была такая же проблема с несколькими файлами, и всегда была проблема, когда люди забывали включить файл «флаг функций» (с базой кода> 41 000 файлов это легко сделать).
Если у вас был feature.h:
Но потом вы забыли включить заголовочный файл в file.cpp:
Тогда у вас есть проблема, компилятор интерпретирует неопределенное значение COOL_FEATURE как «ложь» в этом случае и не может включить код. Да, gcc поддерживает флаг, который вызывает ошибку для неопределенных макросов ... но большая часть стороннего кода либо определяет, либо не определяет функции, поэтому это не будет переносимым.
Мы приняли переносимый способ исправления в этом случае, а также протестировали состояние функции: макросы функций.
если вы изменили вышеуказанный feature.h на:
Но потом вы снова забыли включить заголовочный файл в file.cpp:
В препроцессоре произошла ошибка из-за использования макроса неопределенной функции.
источник
Для целей условной компиляции #if и #ifdef почти одинаковы, но не совсем. Если ваша условная компиляция зависит от двух символов, то #ifdef также не будет работать. Например, предположим, что у вас есть два символа условной компиляции, PRO_VERSION и TRIAL_VERSION, у вас может быть что-то вроде этого:
Использование #ifdef становится намного сложнее, особенно для того, чтобы заставить работать часть #else.
Я работаю над кодом, который широко использует условную компиляцию, и у нас есть смесь #if и #ifdef. Мы склонны использовать # ifdef / # ifndef для простого случая и #if, когда оцениваются два или более символа.
источник
#if defined
чемdefined
это ключевое слово или?Я думаю, это полностью вопрос стиля. Ни у одного из них нет очевидного преимущества перед другим.
Последовательность важнее, чем любой конкретный выбор, поэтому я бы рекомендовал вам собраться вместе со своей командой и выбрать один стиль и придерживаться его.
источник
Сам предпочитаю:
Поскольку это упрощает создание кода, который ищет противоположное условие, гораздо легче обнаружить:
vs.
источник
#if ! defined
чтобы сделать!
более заметным и трудно пропустить.Это вопрос стиля. Но я рекомендую более лаконичный способ сделать это:
Вы делаете это один раз, а затем всегда используете debug_print (), чтобы либо печатать, либо ничего не делать. (Да, это будет компилироваться в обоих случаях.) Таким образом, ваш код не будет искажен директивами препроцессора.
Если вы получили предупреждение «выражение не действует» и хотите от него избавиться, вот альтернатива:
источник
#if
дает вам возможность установить для него значение 0, чтобы отключить функциональность, при этом обнаруживая, что переключатель присутствует.Лично я всегда
#define DEBUG 1
могу поймать это с помощью #if или #ifdefисточник
#define DEBUG 1
. Not#define DEBUG=1
#if и #define MY_MACRO (0)
Использование #if означает, что вы создали макрос «определить», т. Е. Что-то, что будет искать в коде и заменить на «(0)». Это «ад макросов», который я ненавижу видеть в C ++, потому что он загрязняет код потенциальными модификациями кода.
Например:
дает следующую ошибку на g ++:
Только одна ошибка.
Это означает, что ваш макрос успешно взаимодействовал с вашим кодом C ++: вызов функции был успешным. В этом простом случае это забавно. Но мой собственный опыт с макросами, незаметно играющими с моим кодом, не полон радости и наполнения, так что ...
#ifdef и #define MY_MACRO
Использование #ifdef означает, что вы что-то «определяете». Не то чтобы вы придали этому значение. Он по-прежнему загрязняет окружающую среду, но, по крайней мере, он будет «ничем не заменен» и не будет восприниматься кодом C ++ как запаздывающий оператор кода. Тот же код выше с простым определением:
Дает следующие предупреждения:
Так...
Вывод
Я бы предпочел жить без макросов в моем коде, но по нескольким причинам (определение защиты заголовков или отладка макросов) я не могу.
Но, по крайней мере, мне нравится делать их как можно менее интерактивными с моим законным кодом C ++. Это означает использование #define без значения, использование #ifdef и #ifndef (или даже #if, определенных как было предложено Джимом Баком), и, прежде всего, присвоение им таких длинных и чужеродных имен, которые никто в здравом уме не будет использовать. это «случайно», и это никоим образом не повлияет на законный код C ++.
Пост скриптум
Теперь, когда я перечитываю свой пост, мне интересно, не стоит ли мне пытаться найти какое-то значение, которое никогда не будет правильным C ++, чтобы добавить к моему определению. Что-то вроде
который можно использовать с #ifdef и #ifndef, но не позволять коду компилироваться, если он используется внутри функции ... Я успешно попробовал это на g ++, и он дал ошибку:
Интересный. :-)
источник
Это вообще не вопрос стиля. К сожалению, вопрос неверный. Вы не можете сравнивать эти директивы препроцессора в смысле «лучше» или «безопаснее».
означает «если макрос определен» или «если макрос существует». Значение макроса здесь не имеет значения. Это может быть что угодно.
если всегда сравнивать со значением. В приведенном выше примере это стандартное неявное сравнение:
пример использования #if
теперь вы можете поместить определение CFLAG_EDITION либо в свой код
или вы можете установить макрос как флаг компилятора. Также смотрите здесь .
источник
Первое кажется мне более ясным. Кажется более естественным сделать его флагом по сравнению с определенным / не определенным.
источник
Оба абсолютно эквивалентны. В идиоматическом использовании #ifdef используется только для проверки определенности (и того, что я бы использовал в вашем примере), тогда как #if используется в более сложных выражениях, таких как #if defined (A) &&! Defined (B).
источник
Немного ОТ, но включение / выключение протоколирования с помощью препроцессора определенно неоптимально для C ++. Существуют хорошие инструменты для ведения журнала, такие как Apache log4cxx, которые имеют открытый исходный код и не ограничивают способ распространения вашего приложения. Они также позволяют изменять уровни ведения журнала без перекомпиляции, имеют очень низкие накладные расходы, если вы отключите выход, и дают вам возможность полностью отключить выход в производственный процесс.
источник
Раньше я использовал
#ifdef
, но когда я переключился на Doxygen для документации, я обнаружил, что закомментированные макросы не могут быть задокументированы (или, по крайней мере, Doxygen выдает предупреждение). Это означает, что я не могу задокументировать макросы переключения функций, которые в настоящее время не включены.Хотя можно определить макросы только для Doxygen, это означает, что макросы в неактивных частях кода также будут задокументированы. Я лично хочу показать переключатели функций и задокументировать только то, что выбрано в данный момент. Более того, это делает код довольно беспорядочным, если есть много макросов, которые нужно определять только тогда, когда Doxygen обрабатывает файл.
Поэтому в этом случае лучше всегда определять макросы и использовать
#if
.источник
Я всегда использовал #ifdef и флаги компилятора для его определения ...
источник
В качестве альтернативы вы можете объявить глобальную константу и использовать C ++ if вместо препроцессора #if. Компилятор должен оптимизировать для вас неиспользуемые ветки, и ваш код будет чище.
Вот что говорит Стивен С. Дьюхерст о C ++ Gotchas об использовании # if.
источник
Есть разница в случае другого способа указать условное определение для драйвера:
вывод:
Это означает, что
-DA
это синоним,-DA=1
и если значение не указано, это может привести к проблемам в случае#if A
использования.источник
Мне нравится,
#define DEBUG_ENABLED (0)
когда вам может понадобиться несколько уровней отладки. Например:Облегчает отладку утечек памяти, так как все эти строки журнала не мешают отладке других вещей.
Кроме того,
#ifndef
вокруг определения упрощается выбор определенного уровня отладки в командной строке:Если бы не это, я бы дал преимущество,
#ifdef
потому что флаг компилятора / make был бы переопределен флагом в файле. Так что вам не нужно беспокоиться об изменении заголовка перед выполнением фиксации.источник