Зачем использовать макрос+0!=0
в моей текущей кодовой базе я вижу следующий шаблон:
#if SOMETHING_SUPPORTED+0 != 0
...
#endif
к сожалению, это очень старая база кода и никто не знает, как и почему она началась. Я думаю, что это началось в C, и он был медленно преобразован в C с классами, и теперь он имеет тенденцию к C++
Я не вижу очевидного преимущества использования предыдущей конструкции вместо "классического", но, возможно, мне чего-то не хватает:
#if SOMETHING_SUPPORTED
...
#endif
знаете ли вы, почему бы использовать #if MACRO+0 != 0
вместо #if MACRO
?
4 ответа:
ключ здесь в том, что кодовая база очень старая.
этот трюк, вероятно, существует, потому что код когда-то был портирован на компилятор с каким-то очень старым препроцессором, который не обрабатывает неопределено макросы как 0 в препроцессор
#if
условные.то есть, по состоянию на 1989 ANSI C было стандартизировано, что если мы имеем:
#if foo + bar-xyzzy
директива подлежит замене макроса, так что если
foo
,bar
илиxyzzy
это макросы, они заменяются. Затем все оставшиеся идентификаторы, которые не были заменены, заменен0
. Так что еслиfoo
определяется как42
, аbar
иxyzzy
не определены вообще, мы получаем:#if 42 + 0 - 0
а не, скажем, плохой синтаксис:
#if 42 + -
или какое-то другое поведение, например диагностика о
bar
не определены.на препроцессоре, где неопределенные макросы обрабатываются как пробелы,
#if SOMETHING_SUPPORTED
расширяется до просто#if
, что тогда ошибочно.это единственный способ, которым это
IDENT+0
трюк имеет какой-то реальный смысл. Вы просто никогда не захотите этого делать, если вы можете полагаться на то, что предварительная обработка соответствует ISO C.причина в том, что если
SOMETHING_SUPPORTED
ожидается, что у него будут числовые значения, ошибочно разбросано, чтобы определить его как просто пустой. В идеале вы хотите определить, когда это произошло, и остановить компиляцию с помощью диагностический.во-вторых, если вы do поддержка такого рассеянного использования, вы почти наверняка хотите, чтобы явно определенный, но пустой символ вел себя так, как если бы он имел значение 1, а не значение 0. В противном случае, вы создаете ловушку. Кто-то может сделать это в командной строке компилятора:
-DSOMETHING_SUPPORTED=$SHELL_VAR # oops, SHELL_VAR expanded to nothing
или в код:
#define SOMETHING_SUPPORTED /* oops, forgot "1" */
никто не собирается добавить a
#define
или-D
для символа с целью поворота выкл функция, которую он контролирует! Программист, который вставляет#define SOMETHING_SUPPORTED
без1
будет удивлен поведением#if SOMETHING_SUPPORTED+0
который пропускает материал, который должен был быть включен.
вот почему я подозреваю, что немногие программисты C, читающие это, когда-либо видели такое использование, и почему я подозреваю, что это просто обходной путь для поведения препроцессора, чей предполагаемый эффект-пропустить блок, если
SOMETHING_SUPPORTED
отсутствует. Дело в том, что он закладывает "ловушку программиста" -это просто побочный эффект обходного пути.чтобы обойти такую проблему препроцессора без создания ловушки программиста, нужно иметь где-то в начале единицы перевода следующее:
#ifndef SOMETHING_SUPPORTED #define SOMETHING_SUPPORTED 0 #endif
а потом в другом месте просто использовать
#if SOMETHING_SUPPORTED
. Может быть, этот подход не приходил в голову оригинальному программисту, или, возможно, этот программист думал, что+0
трюк был аккуратным, и придавал значение его самоограничению.
#if X+0 != 0
отличается от#if X
в случаеX
определяется как пустой (Примечание: это отличается от случаяX
не определены), например:#define X #if X // error #if X+0 != 0 // no error; test fails
очень часто определяют пустые макросы: конфигурация проекта может генерировать некоторый общий заголовок, содержащий кучу строк
#define USE_FOO
,#define USE_BAR
включить функции, которые поддерживает система, и так далее.The
!= 0
избыточна, код мог бы просто быть#if X+0
.
Итак, преимущество использования
#if X+0
, что еслиX
определяется как пустой, затем компиляция продолжается с пропущенным блоком, а не вызывает ошибку.является ли это хорошей идеей спорно, лично я бы использовал
#ifdef
для логических макросов типаUSE_SOME_FEATURE
и#if
для макросов, где значение может быть диапазоном целых чисел, например; и я хотел бы видеть ошибку, если я случайно использую#if
С чем-то определено как пустое.