2010-09-26 1 views
2

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

#ifndef MYHEADER 

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

ответ

6

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

Однако конвенция должна использовать все шапки для символов препроцессора.

+0

Спасибо! Конечно! Теперь это очевидно, не знаю, почему это меня раньше не поразило. Это определено после ifndef, так что .. Ха, спасибо! – foo

0

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

+0

Спасибо, теперь все ясно. – foo

1

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

+0

Спасибо, он, наконец, нажал на меня. Я просто не заметил (странно), что определение происходит после ifndef. Я как-то посмотрел на неправильное место, считая, что имя файла будет разрешено во всех шапках ifndef. – foo

1

Google для «include guard», чтобы найти то, что вещь на самом деле о.

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

+0

Да, я понимаю соглашение для констант. Но почему-то пропустил #define после #ifndef. – foo

6

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

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

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

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

Дополнительная информация об этом материале here.

1

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

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

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

+1

Избегайте подчеркивания в защитниках заголовков (и, в общем, для идентификаторов, за которыми следует заглавная буква); см. мой ответ для деталей. –

0

Это полностью субъективно, и нет никаких принудительных правил, отличных от тех, которые обычно связаны с набором символов для именования макропрограмм препроцессора. Обычно для макросов можно определить в верхнем регистре. Это, как правило, помогает им выделяться в исходном коде. Соглашением, к которому я склонен придерживаться, является строгая капитализированная версия имени файла с замененным периодом подчеркиванием и ведущими и завершающими символами подчеркивания. Так, файл называется 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++, который будет жаловаться на него, если он не прокомментирован.

+2

Избегайте подчеркивания в защитниках заголовков (и, в общем, для идентификаторов, за которыми следует заглавная буква); см. мой ответ для деталей. –