Ответ 1
gcc может генерировать предупреждение для этого, но его, вероятно, не требуется по стандарту:
-Wundef
Предупреждать, если идентификатор undefined оценивается в директиве `#if '.
Я иногда пишу код примерно так:
// file1.cpp
#define DO_THIS 1
#if DO_THIS
// stuff
#endif
Во время разработки кода я могу переключить определение DO_THIS
между 0 и 1.
Недавно мне пришлось перестроить исходный код и скопировать код из одного файла в другой. Но я обнаружил, что совершил ошибку, и две части разделились так:
// file1.cpp
#define DO_THIS 1
и
// file2.cpp
#if DO_THIS
// stuff
#endif
Очевидно, я исправил ошибку, но потом подумал: почему компилятор не предупредил меня? У меня установлен уровень предупреждения 4. Почему не подозрительно #if X
, когда X не определен?
Еще один вопрос: есть ли какой-либо систематический способ узнать, совершил ли я ту же ошибку в другом месте? Проект огромен.
EDIT: я понимаю, что без предупреждения С#ifdef это имеет смысл. Но, конечно, #if отличается.
gcc может генерировать предупреждение для этого, но его, вероятно, не требуется по стандарту:
-Wundef
Предупреждать, если идентификатор undefined оценивается в директиве `#if '.
Опять же, как это часто бывает, ответ на вопрос "почему" справедлив: так было сделано, потому что некоторое время назад было решено сделать это таким образом. Когда вы используете макрос undefined в #if
, он заменяется на 0. Вы хотите знать, действительно ли оно определено - используйте директиву defined()
.
Есть некоторые интересные преимущества для этого подхода "по умолчанию 0". Особенно, когда вы используете макросы, которые могут быть определены платформой, а не ваши собственные макросы.
Например, некоторые платформы предлагают макросы __BYTE_ORDER
, __LITTLE_ENDIAN
и __BIG_ENDIAN
для определения их соответствия. Вы можете написать директиву препроцессора, например
#if __BYTE_ORDER == __LITTLE_ENDIAN
/* whatever */
#else
/* whatever */
#endif
Но если вы попытаетесь скомпилировать этот код на платформе, которая вообще не определяет эти нестандартные макросы (т.е. ничего не знает о них), вышеуказанный код будет переведен препроцессором в
#if 0 == 0
...
а версия кода младшего порядка будет скомпилирована "по умолчанию". Если вы написали оригинальный #if
как
#if __BYTE_ORDER == __BIG_ENDIAN
...
тогда большая версия кода будет скомпилирована "по умолчанию".
Я не могу сказать, что #if
был определен так, как это было специально для трюков, подобных приведенному выше, но оно время от времени приходит.
Компилятор не генерировал предупреждение, потому что это директива препроцессора. Он оценил и разрешил до того, как компилятор увидит его.
Если вы не можете использовать компилятор с предупреждающим сообщением (например, -Wundef in gcc), я нашел один из полезных способов генерации ошибок компилятора.
Конечно, вы всегда можете написать:
#ifndef DO_THIS
error
#endif
#if DO_THIS
Но это действительно раздражает
Несколько менее раздражающий метод:
#if (1/defined(DO_THIS) && DO_THIS)
Это приведет к делению на нулевую ошибку, если DO_THIS - undefined. Этот метод не идеален, потому что идентификатор выдается дважды, а второй ордер во второй раз вернет нас туда, где мы начали. Это выглядит странно. Кажется, должен быть более чистый способ сделать это, например:
#define PREDEFINED(x) ((1/defined(x)) * x)
#if PREDEFINED(DO_THIS)
но это фактически не работает.
Если вы отчаянно пытаетесь предотвратить такую ошибку, попробуйте следующее, в котором используется проверка маркера и прокрутки маркера в препроцессоре для обеспечения того, чтобы макрос был определен (и 0 в этом примере):
#define DEFINED_VALUE(x,y) (defined (y##x) ? x : 1/x)
#if DEFINED_VALUE(FEATURE1,) == 0
Рекурсивная проблема. Если у вас есть
#define MODEL MODEL_A
#if (MODEL == MODEL_B)
// Surprise, this is compiled!
#endif
где отсутствуют определения MODEL_A и MODEL_B, тогда он будет компилироваться.
#ifdef MODEL
#error Sorry, MODEL Not Defined
// Surprise, this error is never reached (MODEL was defined by undefined symbol!)
#endif
#ifdef MODEL_B
#error Sorry, MODEL_B Not Defined
// This error is reached
#endif
Если я думаю об этом правильно.
Директивы препроцессора обрабатываются до того, как будет скомпилирован исходный код. Во время этой фазы (ов) перевода, в которой это происходит, все директивы препроцессора, макросы и т.д. Обрабатываются, а затем скомпилирован фактический исходный код.
Так как #if используется для определения определения X и выполнения какого-либо действия, если оно определено или не определено. #if в фрагменте кода будет компилироваться без каких-либо ошибок, потому что ошибок в компиляторе нет. Вы всегда можете создать файл заголовка с определенными #defines, которые потребуются вашему приложению, а затем включить этот заголовок.