Почему #ifndef и #define используются в заголовочных файлах C ++?


496

Я видел код, как это обычно в начале заголовочных файлов:

#ifndef HEADERFILE_H
#define HEADERFILE_H

И в конце файла

#endif

Какова цель этого?


36
+1 - у меня тоже были такие же сомнения, и я получил гораздо более хороший ответ, может быть полезен для будущих посетителей: stackoverflow.com/q/3246803/1134940
Абид Рахман K

6
Я хочу добавить к этому, что вы также можете использовать #pragma один раз , это все, что вам нужно сделать, и это служит той же цели, что и ifndef. Для сравнения, смотрите: stackoverflow.com/questions/1143936/…
Измерение

3
Лучше всего упомянуть, что это #pragmaтакое: оно активирует специфическую для компилятора функцию. Хотя #pragma onceэто очень широко поддерживаются, это нестандартное.
Potatoswatter

3
@Dimension: собственная документация GNU ( info cppили посмотрите здесь ) гласит: «она не распознается всеми препроцессорами, поэтому вы не можете положиться на нее в переносимой программе». А GNU cpp оптимизирует обычные и переносимые #ifndefидиомы, поэтому он так же эффективен, как и #pragma once.
Кит Томпсон,

3
Некоторые вещи для рассмотрения: не используйте имя макроса, начинающееся с подчеркивания; такие идентификаторы зарезервированы для реализации. Более тонко, #ifndef HEADERFILE_Hможет нарушить пространство имен реализации заголовка, имя которого начинается с E; идентификаторы, начинающиеся с Eцифры и заглавной буквы, зарезервированы для <errno.h>. Я предлагаю #ifndef H_HEADERFILE.
Кит Томпсон

Ответы:


527

Это называется #include guard .

Как только заголовок включен, он проверяет, определено ли уникальное значение (в данном случае HEADERFILE_H). Затем, если он не определен, он определяет его и переходит к остальной части страницы.

Когда код включается снова, первый ifndefсбой, в результате чего пустой файл.

Это предотвращает двойное объявление любых идентификаторов, таких как типы, перечисления и статические переменные.


1
Koning Baard XIV: у VC даже есть тот, #pragma onceкоторый делает то же самое :-)
Joey

95
Также он предотвращает рекурсивные включения ... Представьте себе, что alice.h включает в себя «bob.h», а «bob.h» включает в себя «alice.h», и они не включают в себя охранников ...
Кевин Дунгс

@Kevin: это то, что я имею в виду. Я хотел манипулировать формой, которая открывалась формой для манипулирования. Это дало мне много ошибок, и я не знал, что делать. Я сдался =)

6
@ Јоее: #pragma onceне переносимый; общая #ifndefидиома рекомендуется.
Кит Томпсон,

2
@CIsForCookies Вставьте «одно правило определения» в вашу любимую поисковую систему.
Дэвид Шварц

33
#ifndef <token>
/* code */
#else
/* code to include if the token is defined */
#endif

#ifndefпроверяет, был ли данный токен #definedранее в файле или во включенном файле; если нет, он включает код между ним и закрывающим #elseили, если нет #else, #endifоператором. #ifndefчасто используется для придания идемпотентности заголовочных файлов путем определения токена после включения файла и проверки того, что токен не был установлен вверху этого файла.

#ifndef _INCL_GUARD
#define _INCL_GUARD
#endif

4
Идентификаторы, начинающиеся с подчеркивания, зарезервированы; Вы не должны определять их сами. Используйте что-то вроде #ifndef H_HEADER_NAME.
Кит Томпсон,

5
Я знаю, что это старый комментарий, но на самом деле ограничение подчеркивания относится только к «внешним идентификаторам» - идентификаторам, которые могут оказаться в таблице символов скомпилированного объекта, то есть в глобальных переменных и именах функций. Это не относится к именам макросов.
Stu

1
Является ли комментарий Стю правдой? Я только что прочитал stackoverflow.com/questions/228783/… и теперь я не так уверен.
Уилл

10

Это предотвращает многократное включение одного и того же заголовочного файла несколько раз.

#ifndef __COMMON_H__
#define __COMMON_H__
//header file content
#endif

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

В следующий раз __COMMON_H__ определен, поэтому он не будет включаться снова.


1

Они называются ifdef или включают охранников.

При написании небольшой программы может показаться, что она не нужна, но по мере роста проекта вы можете намеренно или неумышленно включать один файл много раз, что может привести к предупреждению компиляции, как уже объявленная переменная.

#ifndef checks whether HEADERFILE_H is not declared.
#define will declare HEADERFILE_H once #ifndef generates true.
#endif is to know the scope of #ifndef i.e end of #ifndef

Если он не объявлен, что означает, что #ifndef генерирует true, тогда только часть между #ifndef и #endif выполняется иначе. Это предотвратит повторное объявление идентификаторов, перечислений, структуры и т. Д.

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