Что именно делает блок #if 0… #endif?


124

В C / C ++

Что происходит с кодом, помещенным между блоком #if 0/ #endif?

#if 0

//Code goes here

#endif

Код просто пропускается и, следовательно, не выполняется?


17
Это метод, используемый для комментирования больших объемов кода или для проверки включения блоков кода. Без этой функции нужно было бы либо префикс каждой строки, //либо начинать раздел с /*и заканчивать раздел с */. Проблема с последними методами заключается в том, что комментарии не вкладываются, поэтому разработчик должен проверять и обрабатывать любые данные */между началом и концом.
Thomas Matthews

Ответы:


141

Он не только не выполняется, он даже не компилируется.

#if- это команда препроцессора, которая оценивается перед фактическим шагом компиляции. Код внутри этого блока не отображается в скомпилированном двоичном файле.

Он часто используется для временного удаления сегментов кода с намерением включить их позже.


1
Это верно в отношении любых комментариев. Важное отличие - это вложенность.
Samy Bencherif

73

Это идентично закомментированию блока, за исключением одного важного различия: вложение не является проблемой. Рассмотрим этот код:

foo();
bar(x, y); /* x must not be NULL */
baz();

Если я хочу это прокомментировать, я могу попробовать:

/*
foo();
bar(x, y); /* x must not be NULL */
baz();
*/

Bzzt. Ошибка синтаксиса! Зачем? Поскольку блочные комментарии не вкладываются, и поэтому (как вы можете видеть из выделения синтаксиса SO) */после слова «NULL» комментарий завершается, и bazвызов не закомментирован, а */после baz- синтаксическая ошибка. С другой стороны:

#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif

Работает, чтобы закомментировать все это. И #if 0s будут гнездиться друг с другом, например:

#if 0
pre_foo();
#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif
quux();
#endif

Хотя, конечно, это может немного сбить с толку и стать головной болью при обслуживании, если не прокомментировать должным образом.


5
Просто обратите внимание, что код внутри #if должен быть лексически правильным (в отличие от комментариев), и директивы препроцессора все еще действуют (то же самое).
jpalecek

@David: Это неверно с лексики, но все равно будет компилироваться. Так что код не обязательно должен быть лексически правильным.
Деннис Зикефуз

1
@ Деннис, я получаю foo.c:3: unterminated string or character constantот gcc, что ты используешь?
Дэвид Икс

18

Он постоянно комментирует этот код, поэтому компилятор никогда его не скомпилирует.

Кодер может позже изменить #ifdef, чтобы этот код компилировался в программе, если он захочет.

Как будто кода не существует.


14

Что именно делает блок #if 0… #endif?

Это говорит вам, что автор, очевидно, никогда не слышал о системе контроля версий. Что, в свою очередь, говорит вам бежать как можно дальше ...


12

Хочу добавить по #elseделу:

#if 0
   /* Code here will NOT be complied. */
#else
   /* Code will be compiled. */
#endif


#if 1
   /* Code will be complied. */
#else
   /* Code will NOT be compiled. */
#endif

7

Когда препроцессор видит #if, он проверяет, имеет ли следующий токен ненулевое значение. Если это так, он сохраняет код для компилятора. Если это не так, он избавляется от этого кода, поэтому компилятор никогда его не видит.

Если кто-то говорит #if 0, они фактически комментируют код, поэтому он никогда не будет скомпилирован. Вы можете думать об этом так же, как если бы они поместили вокруг него / * ... * /. Это не совсем то же самое, но имеет тот же эффект.

Если вы хотите подробно разобраться в произошедшем, можете часто посмотреть. Многие компиляторы позволяют просматривать файлы после запуска препроцессора. Например, в Visual C ++ команда switch / P выполнит препроцессор и поместит результаты в файл .i.


Не совсем. Препроцессор выполняет синтаксический анализ по строкам, а не по токенам. Согласно вашему объяснению, нельзя сказать, например, #if WIN32 || __CYGWIN__но это работает должным образом.
Бен Фойгт

Я упрощал. Если есть или, он проверит, не равен ли какой-либо токен нулю. Точно так же, если есть и, он проверит, не равны ли оба значения.
Стив Роу

3

Строки, начинающиеся с a, #являются директивами препроцессора . #if 0 [...] #endifблоки не попадают в компилятор и не генерируют машинный код.

Вы можете продемонстрировать, что происходит с препроцессором с исходным файлом ifdef.cxx:

#if 0
This code will not be compiled
#else
int i = 0;
#endif

Запуск gcc -E ifdef.cxxпокажет вам, что компилируется.

Вы можете использовать этот механизм для предотвращения компиляции блока кода во время цикла разработки, но вы, вероятно, не захотите регистрировать его в системе управления версиями, поскольку он просто добавляет беспорядка в ваш код и снижает удобочитаемость. Если это исторический фрагмент кода, который был закомментирован, его следует удалить: система управления версиями содержит историю, верно?

Кроме того, ответ может быть одинаковым как для C, так и для C ++, но языка C / C ++ не существует, и ссылаться на такой язык - не лучшая привычка.


4
Что плохого в том, чтобы говорить «C / C ++» как сокращение от «C или C ++»? Вы действительно думаете, что кто-то запутается, если подумает, что существует язык под названием "C / C ++"?
Кристофер Барбер,

1
@Chris: Люди постоянно задают вопросы вроде «Как мне использовать X в C / C ++?» Это бессмысленный вопрос; вы кодируете то или другое, и если вы еще не выбрали этот вариант, вы должны четко заявить об этом. Итак, да, люди сбиты с толку из-за того, что существует язык под названием «C / C ++»
Деннис Зикефуз

1
Что за бессмысленное заявление! Есть тысячи вопросов, ответы на которые относятся как к C, так и к C ++. Помните, что это сайт для вопросов. Тот факт, что вы задаете общий вопрос, не означает, что вы не знаете, какой язык используете. Если вы подозреваете, что это так, как в этом вопросе, как это помогает указать C или C ++? Как вы думаете, было бы полезно, если бы каждый вопрос, который может относиться к C или C ++, задавался дважды?
Кристофер Барбер

@Christopher: Вы правы, есть много вопросов, ответы на которые так же актуальны для C, C ++ и Objective-C (это один из них). У Stack Overflow есть удобная система тегов, чтобы обозначить, к какому языку относится вопрос. Как упоминает @Dennis, SO (и другие форумы по программированию [форумы?]) Есть (слишком) много людей, которых смущает разграничение между C и другими производными от C языками, которые называют эти языки взаимозаменяемыми как C / C ++, что делает его сложнее ответить на вопрос на соответствующем языке.
Johnsyweb

2

Не совсем

int main(void)
{
   #if 0
     the apostrophe ' causes a warning
   #endif
   return 0;
}

Он показывает «tc: 4: 19: предупреждение: отсутствует завершающий символ» с gcc 4.2.4.


2
Это предупреждение генерируется препроцессором, а не компилятором. Компилятор видит только: # 1 "tc" # 1 "<built-in>" # 1 "<command-line>" # 1 "tc" int main (void) {return 0; }
Johnsyweb

0

Это дешевый способ прокомментировать, но я подозреваю, что он может иметь отладочный потенциал. Например, предположим, что у вас есть сборка, которая выводит значения в файл. Возможно, вы не захотите этого в окончательной версии, поэтому вы можете использовать #if 0 ... #endif.

Кроме того, я подозреваю, что лучший способ сделать это для целей отладки - это сделать:

#ifdef DEBUG
// output to file
#endif

Вы можете сделать что-то подобное, и это может иметь больше смысла, и все, что вам нужно сделать, это определить DEBUG, чтобы увидеть результаты.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.