Директива препроцессора #ifndef для кода C / C ++ - PullRequest
15 голосов
/ 11 мая 2010

В eclipse всякий раз, когда я создаю новый класс 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 или просто пример? В этом есть что-то особенное, или это может быть просто артефакт того, как eclipse предпочитает автоматически создавать проекты?

Ответы [ 8 ]

14 голосов
/ 11 мая 2010

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

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

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

4 голосов
/ 11 мая 2010

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

#define MYPROJ_EXAMPLE_H

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

4 голосов
/ 11 мая 2010

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

2 голосов
/ 11 мая 2010

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

Файл foo.c:

#include foo.h
#include bar.h

Файл bar.h

#include <iostream>
#include foo.h

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

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

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

2 голосов
/ 11 мая 2010

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

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

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

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

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

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

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

2 голосов
/ 11 мая 2010

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

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

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

1 голос
/ 03 декабря 2012

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

0 голосов
/ 11 мая 2010

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

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

#ifndef __MYPROJECT_EXAMPLE_H__
...
...