Зачем использовать макрос+0!=0


в моей текущей кодовой базе я вижу следующий шаблон:

#if SOMETHING_SUPPORTED+0 != 0
...
#endif

к сожалению, это очень старая база кода и никто не знает, как и почему она началась. Я думаю, что это началось в C, и он был медленно преобразован в C с классами, и теперь он имеет тенденцию к C++

Я не вижу очевидного преимущества использования предыдущей конструкции вместо "классического", но, возможно, мне чего-то не хватает:

#if SOMETHING_SUPPORTED
...
#endif

знаете ли вы, почему бы использовать #if MACRO+0 != 0 вместо #if MACRO?

4 72

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 С чем-то определено как пустое.

давайте сделаем таблицу!

X       #if X     #if X+0 != 0
<undef> false     false
<empty> error     false
0       false     false
1       true      true
2       true      true
a       false     false
xyz     false     false
12a     error     error
12 a    error     error
+0 != 0 вариант раньше.

это другой способ написания

 #if defined(MACRO) && MACRO != 0

+0 есть, чтобы убедиться, что результат-это число. Если MACRO не определено, это позволяет избежать ошибки в результате #if MACRO != 0.

плохое качество вещи, но не связывайтесь с ним, если вы не должны.