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

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

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

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

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

  • Что такое EXAMPLE_H_? Почему не example.h, или просто пример? Есть ли что-то особенное в этом вопросе или может быть просто артефактом того, как eclipse предпочитает авто-строить проекты?

Ответы

Ответ 1

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

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

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

Ответ 2

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

Ответ 3

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

#define MYPROJ_EXAMPLE_H

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

Ответ 4

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

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

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

Ответ 5

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

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

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

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

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

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

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

Ответ 6

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

Файл foo.c:

#include foo.h
#include bar.h

Файл bar.h

#include <iostream>
#include foo.h

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

Чтобы предотвратить это, мы положим INCLUDE GUARD вверху. Таким образом, если он уже включен, мы определяем переменную препроцессора, чтобы сообщить нам не включать ее снова.

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

Ответ 7

U люди означают, что я должен разместить защиту заголовка для каждого файла заголовка, который я хочу включить i, e.. я имеет следующие заголовочные файлы для включения abc.h и def.h, чем я должен разместить заголовок заголовка следующим образом         #ifndef abc_h          #define abc_h и           #ifndef def_h           #define def_h

Ответ 8

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

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

#ifndef __MYPROJECT_EXAMPLE_H__
...