C ++ #ifndef для включаемых файлов, почему все заглавные буквы используются для заголовочного файла? - PullRequest
2 голосов
/ 26 сентября 2010

Интересно, почему имя после директивы #ifndef всегда содержит заглавные буквы и не соответствует имени фактического заголовочного файла? Каковы правила, окружающие это? Я искал вокруг сети, но я не нашел никакого объяснения этому. Если мой заголовочный файл называется myheader.h, тогда можно использовать:

#ifndef MYHEADER

Если так, то почему? Какие правила?

Ответы [ 7 ]

6 голосов
/ 26 сентября 2010

Нет "правила", есть только условности.Первое и наиболее используемое соглашение состоит в том, что все макросы прекомпилятора все в верхнем регистре, поэтому элементы защиты заголовка тоже должны быть в верхнем регистре.

Что касается имени макроса, что я использую (и какую часть кода я виделИспользуется) - это просто имя заголовка (как сказано, обращено ко всем заглавным буквам), включая расширение, заменяя точку подчеркиванием, за которым следует _INCLUDED.

#ifndef MYHEADER_HPP_INCLUDED
#define MYHEADER_HPP_INCLUDED
// ...
#endif

. Обратите внимание, что многие предшествуют таким идентификаторам с помощьюподчеркивание или двойное подчеркивание, но это не очень хорошая практика, поскольку в стандарте указывается, что идентификаторы, начинающиеся (или содержащие) двойные подчеркивания, а идентификаторы, начинающиеся с единственного подчеркивания, за которым следует заглавная буква, зарезервированы для вещей, специфичных для компилятора / библиотеки (например, __declspec).в VC ++ или макросах, используемых в стандартных заголовках) во всех областях;все остальные идентификаторы, начинающиеся с одного подчеркивания, зарезервированы в глобальной области видимости.Поэтому такие идентификаторы не должны использоваться, чтобы избежать коллизий.

Подробнее об этом здесь .

6 голосов
/ 26 сентября 2010

Это символы препроцессора и не имеют таких правил.(до тех пор, пока они совпадают с #defines в заголовках)

Однако принято использовать заглавные буквы для символов препроцессора.

1 голос
/ 26 сентября 2010

Идея состоит в том, чтобы убедиться, что ваш заголовочный файл читается только один раз во время сборки.Идиома для достижения этой цели - структура:

   #ifndef _SOME_UNIQUE_NAME
   #define _SOME_UNIQUE_NAME
   /* The actual header code */
   #endif

Это означает, что вы должны выбрать имя, которое, как вы уверены, будет уникальным и является допустимым идентификатором #ifndef.Вы также должны убедиться, что идентификатор не используется в реальном коде или не перепутан с переменной или чем-то еще.Наличие заглавной метки четко обозначает идиому.Кроме того, это просто соглашения, а не язык, который диктует этот выбор.Мастера Visual Studio генерируют GUID-подобный идентификатор для.Компоненты Sone поддерживают #pragma, если имеют тот же эффект.

1 голос
/ 26 сентября 2010

Google для " включает охрану " , чтобы узнать, о чем идет речь.

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

1 голос
/ 26 сентября 2010

Не обязательно быть всеми заглавными буквами.Это просто общее соглашение.Я обычно использую что-то вроде #ifndef MYHEADER_H_INCLUDED.

0 голосов
/ 27 сентября 2010

Это полностью субъективно, и нет никаких обязательных правил, кроме тех, которые обычно связаны с набором символов для именования макросов препроцессора. Обычно макрос определяется в верхнем регистре. Это помогает им выделяться в исходном коде. Соглашение, к которому я склонен придерживаться, - это строго прописная версия имени файла с периодом, замененным подчеркиванием, первым и последним подчеркиванием. Таким образом, для файла с именем DataTableNameMangler.hpp защита включения будет выглядеть так:

#ifndef _DATATABLENAMEMANGLER_HPP_
#define _DATATABLENAMEMANGLER_HPP_

...

#endif // _DATATABLENAMEMANGLER_HPP_

Нет веских причин для этого, хотя я настоятельно рекомендую для согласованности, чтобы имя точно совпадало с именем файла. Обычно я использую небольшой сценарий создания классов для генерации своих начальных классов. Следующий фрагмент Bash дает представление:

#!/bin/bash
INC_GUARD_NAME="_${1^^*}_HPP_"
echo "#ifndef $INC_GUARD_NAME"
echo "#ifndef $INC_GUARD_NAME"
echo
echo "class $1 {};"
echo
echo "#endif // $INC_GUARD_NAME"

Таким образом:

$ ./makeclass.bash DataTableNameMangler
#ifndef _DATATABLENAMEMANGLER_HPP_
#ifndef _DATATABLENAMEMANGLER_HPP_

class DataTableNameMangler {};

#endif // _DATATABLENAMEMANGLER_HPP_

Естественно, это очень простой пример. Важно, что не забудьте поставить комментарий перед именем охранника в последней строке. #endif не принимает параметров, поэтому макрос будет передан компилятору C ++, который будет жаловаться на него, если он не закомментирован.

0 голосов
/ 26 сентября 2010

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

...