Ответ 1
Ключевым моментом здесь является то, что база кода очень старая.
Этот трюк, вероятно, существует, потому что один раз код был перенесен в компилятор с очень старым препроцессором, который не обрабатывает макросы undefined как 0 в условных выражениях препроцессора #if
.
То есть, с 1989 ANSI C было стандартизировано, что если мы имеем:
#if foo + bar - xyzzy
директива подлежит замене макроса, поэтому если foo
, bar
или xyzzy
являются макросами, они заменяются. Затем любые оставшиеся идентификаторы, которые не были заменены, заменяются на 0
. Поэтому, если foo
определяется как 42
, но bar
и xyzzy
вообще не определены, мы получаем:
#if 42 + 0 - 0
а не, скажем, плохой синтаксис:
#if 42 + -
или какое-либо другое поведение, например диагностика bar
не определена.
В препроцессоре, где макросы undefined рассматриваются как пробелы, #if SOMETHING_SUPPORTED
расширяется до всего лишь #if
, что затем ошибочно.
Это единственный способ, с помощью которого трюк IDENT+0
делает какой-либо реальный смысл. Вы просто не захотите этого делать, если вы можете полагаться на предварительную обработку, соответствующую ISO C.
Причина в том, что если ожидается, что SOMETHING_SUPPORTED
имеет числовые значения, это ошибочно рассеянно, чтобы определить его как просто пробел. В идеале вы хотите определить, когда это произошло, и прекратить компиляцию с помощью диагностики.
Во-вторых, если вы поддерживаете такое рассеянное использование, вы почти наверняка хотите, чтобы явно определенный, но пустой символ вел себя так, как будто он имел значение 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
был опрятным и помещал значение в его сдерживание.