2015-10-08 2 views
4

Я новичок в написании своих собственных заголовков, но из-за необходимости я должен учиться.Header Вопросы охраны в C++

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

Возьмите этот гипотетический пример: x.h

//x.h 
#ifndef __X_H_INCLUDED__ 
#define __X_H_INCLUDED__ 
//functions n stuff 
#endif 

против:

//x.h 
#ifndef _X_H_INCLUDED_ 
#define _X_H_INCLUDED_ 
//functions n stuff 
#endif 

более или менее верно, чем другой? Есть ли разница?

+4

двойные подчеркивания зарезервированы для реализации - использование их в ваших собственных файлах заголовков является неопределенным поведением и, как правило, не является хорошей идеей. –

+0

Также проверьте '#pragma once' http://stackoverflow.com/questions/1143936/pragma-once-vs-include-guards – Anthony

+2

Это [похоже] (http://stackoverflow.com/a/33005607/4143855), не имея ведущих подчеркиваний, было бы лучше. Почему бы не просто «X_H_INCLUDED»? – Tas

ответ

8

Согласно C++11 17.6.4.3.2 Global names (хотя это ограничение было вокруг на некоторое время):

Некоторые наборы имен и сигнатуры функций всегда зарезервировано для осуществления:

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

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

Было бы «безопаснее» использовать что-то наподобие GUARD_X_H или X_H_INCLUDED, хотя, конечно, вам все равно нужно опасаться столкновений. Вы могли бы взять на себя путь Java и в конечном итоге с помощью макросов, таких как:

AU_COM_POWERFIELD_DATASTRUCTURES_TREES_BALANCED_BTREE_H 

до тех пор, пока вы остаетесь ниже пределов осуществления для имен макросов (которые, по памяти, по крайней мере, 1024 символов).

В качестве альтернативы, если вы хотите пожертвовать портативность (но не много портативности, так как она поддерживается в очень многих компиляторах), вы можете посмотреть в #pragma once, где вам не придется беспокоиться о придумывать уникальные имена.

2

От Standard ++ 2003 C (эти правила все еще применяются):

17.4.3.2.1 Глобальные имена [lib.global.names]

Некоторые наборы имен и сигнатуры функций всегда защищены к внедрению:

каждого имя, которое содержит двойное подчеркивание (_ _) или начинается с подчеркивания с последующим прописной буквой (2.11) резервируется для реализации для любого использования. Каждое имя, которое начинается с символа подчеркивания , зарезервировано для реализации для использования в качестве имени в глобальном пространстве имен .165 165). Такие имена также зарезервированы в пространстве имен :: std (17.4.3.1).

1

Мне нравится следовать определенной структуре для включения охранников, которая соответствует структуре проекта.

#ifndef PROJECT_PATH_TO_FILE_HPP 
// etc. etc. 

Так, если проект называет «кегли», и путь к заголовку является taste/the/rainbow.hpp тогда мой включают охранник становится:

#ifndef SKITTLES_TASTE_THE_RAINBOW_HPP 
// etc. etc. 

Это работает довольно хорошо, вы просто должны быть осторожными имя сталкивается с именами файлов и каталогами. Например, один файл в корне проекта называется foo_bar.hpp, а один - foo/bar.hpp. Это вызовет столкновение имен, которое необходимо будет обработать.

Другим вариантом является использование пространства имен вместо путей:

#define PROJECT_NAMESPACE_MODULE_HPP 

Я также видел, как люди добавить дату и время создания файла, или использовать UUID, чтобы добавить дополнительную безопасность от имени столкновений.