Чому #ifndef та #define використовуються у файлах заголовків C ++?


495

Я зазвичай бачив такий код зазвичай на початку файлів заголовків:

#ifndef HEADERFILE_H
#define HEADERFILE_H

І в кінці файлу є

#endif

Яка мета цього?


36
+1 - У мене теж були сумніви, і я отримав набагато більше гарної відповіді тут, може бути корисним для майбутніх відвідувачів: stackoverflow.com/q/3246803/1134940
Abid Rahman 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.
Кіт Томпсон

Відповіді:


525

Вони називаються охоронцями #include .

Після включення заголовка він перевіряє, чи визначено унікальне значення (у цьому випадку HEADERFILE_H). Потім, якщо це не визначено, він визначає його і продовжує переходити на решту сторінки.

Коли код знову включається, перший ifndefвиходить з ладу, що призводить до появи порожнього файлу.

Це запобігає подвійному оголошенню будь-яких ідентифікаторів, таких як типи, перерахунки та статичні змінні.


Koning Baard XIV: VC навіть має a, #pragma onceякий робить те саме :-)
Joey

95
Крім того, це запобігає рекурсивним включенням ... Уявіть, що "alice.h" включає "bob.h", а "bob.h" включає "alice.h", і вони не включають охоронців ...
Kevin Dungs

@Kevin: саме так я і маю на увазі. Я хотів маніпулювати формою, яка була відкрита формою для маніпулювання. Це дало багато помилок, і я не знав, що робити. Я здався =)

6
@ Јοeу: #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часто використовується для того, щоб зробити заголовкові файли idempotent шляхом визначення токена, як тільки файл включений, і перевірки, що маркер не встановлений у верхній частині цього файлу.

#ifndef _INCL_GUARD
#define _INCL_GUARD
#endif

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

5
Я знаю, що це старий коментар, але насправді обмеження підкреслення стосується лише "зовнішніх ідентифікаторів" - ідентифікаторів, які можуть опинитися в таблиці символів складеного об'єкта, тобто глобальних змінних та імен функцій. Це не стосується макроімен.
Світ

1
Чи правдивий коментар Стю? Я щойно прочитав stackoverflow.com/questions/228783/…, і тепер я не такий впевнений.
Чи буде

9

Це запобігає багаторазовому включенню одного і того ж файлу заголовка кілька разів.

#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 генерує істину, то лише частина між #ifndef та #endif виконана інакше. Це запобіжить повторному оголошенню ідентифікаторів, перерахунків, структури тощо ...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.