Що саме робить блок #if 0… #endif?


124

В C / C ++

Що відбувається з кодом, розміщеним між #if 0/ #endifблоком?

#if 0

//Code goes here

#endif

Чи просто пропускається код і тому не виконується?


17
Це методика, яка використовується для коментування великої кількості коду або для тестування включення блоків коду. Без цієї функції вам доведеться або префіксувати кожен рядок, //або розпочати розділ з /*і закінчити розділ */. Проблема останніх методів полягає в тому, що коментар не гніздиться, тому розробник повинен перевіряти та обробляти будь-яке */між початком і кінцем.
Томас Меттьюз

Відповіді:


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 0гніздяться один з одним, як-от так:

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

Хоча, звичайно, це може заплутатися і стати головним болем, якщо його не коментувати належним чином.


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

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

1
@Dennis, я отримую foo.c:3: unterminated string or character constantвід gcc, що ти використовуєш?
Давид X

18

Він постійно коментує цей код, щоб компілятор ніколи його не компілював.

Пізніше кодер може змінити #ifdef, щоб цей код був зібраний у програмі, якщо він захоче.

Це точно так, як код не існує.


15

Що саме робить блок #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 (це одна з них). Переповнення стека має зручну систему тегів для позначення, до яких мов належить питання. Як згадує @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.