Директива препроцессору #ifndef для кода C/C++

В затмении, каждый раз, когда я создаю новый класс C++ или заголовочный файл C, я получаю следующий тип структуры. Скажите, что я создаю заголовочный файл example.h, я получаю это:

/*Comments*/
#ifndef EXAMPLE_H_
#define EXAMPLE_H_
/* Place to put all of my definitions etc. */
#endif

Я думаю, что ifndef говорит, что, если EXAMPLE_H_ не определяется, определить его, который может быть полезным, в зависимости от какого инструмента Вы используете для компиляции и связываете свой проект. Однако у меня есть два вопроса:

  1. Действительно ли это довольно распространено? Я не вижу его слишком часто. И действительно ли это - хорошая идея использовать ту рубрику, или необходимо ли просто перейти прямо в определение кода.

  2. Что такое EXAMPLE_H_ точно? Почему не example.h, или просто пример? Действительно ли там что-нибудь является особенным об этом, или мог быть просто быть артефактом того, как затмение предпочитает автосоздавать проекты?

16
задан Brian Tompsett - 汤莱恩 24 February 2016 в 14:03
поделиться

7 ответов

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

Помещение обертки #ifndef вокруг содержимого означает, что компилятор разбирает содержимое заголовка только один раз и избегает ошибок переопределения.

Некоторые компиляторы позволяют использовать "#pragma once", чтобы сделать то же самое, но конструкция #ifndef работает везде.

15
ответ дан 30 November 2019 в 17:52
поделиться

Является ли это общепринятым? Да - все заголовочные файлы C и C++ должны быть структурированы подобным образом. EXAMPLE_H - это защита заголовка, она предотвращает включение кода в заголовок более одного раза в одну и ту же единицу трансляции, что привело бы к множественным ошибкам определения. Имя EXAPMLE_H выбирается в соответствии с именем защищаемого заголовочного файла - оно должно быть уникальным в вашем проекте и, возможно, в глобальном масштабе. Чтобы попытаться обеспечить это, нормально префикснуть или суффикснуть его с именем вашего проекта:

#define MYPROJ_EXAMPLE_H

например, если ваш проект называется "myproj". Кстати, не поддавайтесь искушению думать, что префикс с подчеркиванием волшебным образом сделает его уникальным - имена типа _EXAMPLE_H_ и __EXAMPLE_H__ являются незаконными, поскольку они зарезервированы для реализации языка.

4
ответ дан 30 November 2019 в 17:52
поделиться

Всегда делайте это в верхней части файла заголовка. Обычно это называется защитой заголовка или защитой включения.

Что он делает, так это то, что если файл заголовка будет включен несколько раз, он будет включен только один раз. Если вы этого не сделаете, то в конечном итоге получите ошибки о том, что что-то определяется несколько раз, и тому подобное.

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

2
ответ дан 30 November 2019 в 17:52
поделиться

Рассмотрим этот

Файл foo.c:

#include foo.h
#include bar.h

Файл bar.h

#include <iostream>
#include foo.h

Теперь, когда мы компилируем foo.c, у нас есть foo.h дважды! Мы определенно этого не хотим, потому что все функции второй раз будут вызывать ошибки компиляции.

Чтобы предотвратить это, мы поместили ВКЛЮЧИТЬ ЗАЩИТУ вверху. Таким образом, если он уже был включен, мы определяем переменную препроцессора, чтобы не включать ее снова.

Это очень распространено (часто требуется) и очень неприятно, если кто-то не вставляет его туда. Вы должны просто ожидать, что каждый файл .h будет иметь защиту заголовка при включении. Конечно, вы знаете, что они говорят, когда вы предполагаете что-то («насмехается над вами и мной»), но это должно быть то, что вы ожидаете увидеть.

2
ответ дан 30 November 2019 в 17:52
поделиться

Это защита включения. Это гарантирует, что заголовок включен не более одного раза.

Например, если вы:

#include "example.h"
#include "example.h"

При первом включении заголовка, EXAMPLE_H_ не будет определен и будет введен блок if. EXAMPLE_H_ затем определяется директивой #define , и оценивается содержимое заголовка.

При втором включении заголовка EXAMPLE_H_ уже определен, поэтому блок if не вводится повторно.

Это важно, чтобы гарантировать, что вы не нарушите одно правило определения. Если вы определите класс в заголовке, который не имеет включенных охранников и включил этот заголовок дважды, вы получите ошибки компиляции из-за нарушения одного правила определения (класс будет определен дважды).

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

2
ответ дан 30 November 2019 в 17:52
поделиться

Это просто обычный способ защиты ваших включений - таким образом он предотвращает включение кода дважды. И используемый идентификатор может быть любым, это просто соглашение, чтобы сделать это так, как описано.

4
ответ дан 30 November 2019 в 17:52
поделиться

Это называется «защитой включения» и действительно является общей идиомой для файлов заголовков C / C ++. Это позволяет включать файл заголовка несколько раз без многократного включения его содержимого.

Имя EXAMPLE_H_ является произвольным соглашением, но оно должно подчиняться правилам именования макросов препроцессора C, что исключает такие имена, как example.h. Поскольку все макросы C определены в одном глобальном пространстве имен, важно, чтобы у вас не было разных файлов заголовков, которые используют одно и то же имя для своей защиты включения. Поэтому обычно рекомендуется включать имя вашего проекта или библиотеки в имя защиты включения:

#ifndef __MYPROJECT_EXAMPLE_H__
...
0
ответ дан 30 November 2019 в 17:52
поделиться