Является ли #pragma когда-то частью стандарта C ++ 11?


142

Традиционно стандартным и переносимым способом избежать включения нескольких заголовков в C ++ было использование #ifndef - #define - #endifсхемы директив предварительного компилятора, также называемой схемой защиты от макросов (см. Фрагмент кода ниже).

#ifndef MY_HEADER_HPP
#define MY_HEADER_HPP
...
#endif

Однако в большинстве реализаций / компиляторов (см. Рисунок ниже) существует более «элегантная» альтернатива, которая служит той же цели, что и вызванная схема защиты от макросов #pragma once. #pragma onceимеет несколько преимуществ по сравнению со схемой защиты от макросов, в том числе меньший объем кода, предотвращение конфликтов имен и иногда повышенная скорость компиляции.

введите описание изображения здесь

Проведя небольшое исследование, я понял, что хотя #pragma onceдиректива поддерживается почти всеми известными компиляторами, есть неясность в отношении того, #pragma onceявляется ли директива частью стандарта C ++ 11 или нет.

Вопросы:

  • Может ли кто-нибудь уточнить, #pragma onceявляется ли директива частью стандарта С ++ 11 или нет?
  • Если он не является частью стандарта C ++ 11, есть ли планы по его включению в более поздние версии (например, C ++ 14 или новее)?
  • Также было бы неплохо, если бы кто-то мог более подробно рассказать о преимуществах / недостатках использования любого из методов (например, макрозащиты по сравнению с #pragma once).

10
Кстати, использование двойных подчеркиваний для защиты заголовков запрещено стандартом, который резервирует для реализации все символы, начинающиеся с двойного подчеркивания (кроме других).
Маттео Италия

10
Запрещается также использовать начальное подчеркивание, за которым следует заглавная буква. Во-вторых, где же мутность? Я просто вижу поддержку компилятора, я не вижу, чтобы кто-то утверждал, что это часть стандарта?
Якк - Адам Неврамонт

1
Для третьего пункта взгляните на связанный вопрос: #pragma Once безопасный включает охранник? Бывает, что защита жатки работает, но #pragma onceобычно нет.
user1942027

1
возможный дубликат в том, что он отвечает на этот вопрос без упоминания C ++ 11.
Якк - Адам Неврамонт

4
Что ж, это не закодировано ни в одном официальном документе, но вы можете считать его стандартом де-факто .
Сиюань Рен

Ответы:


109

#pragma onceэто не стандарт. Это распространенное (но не универсальное) расширение, которое можно использовать

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

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

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


11
Не только удаленные крепления. Жесткие ссылки, программные ссылки, конструкции подстановки (в Windows). Это может стать действительно беспорядочным.
Тонни

46
Почему компилятор не может использовать контрольные суммы SHA-1 или MD5 для идентификации файлов?
Сергей

30
Я действительно не вижу смысла не включать что-то в стандарт, если это поддерживает каждый крупный компилятор. На самом деле в стандарте есть вещи, которые поддерживаются гораздо меньше, чем это. Кроме того, довольно глупо жаловаться на проблемы с границами, когда мы говорим о включаемых файлах, где конфликты имен файлов уже являются огромной проблемой. Было бы неплохо, если бы эта потребность в 100% беспроблемной функции применялась к концепции #included файлов заголовков в целом.
TED

39
Если ваш код включает какой-то файл из разных мест через символические ссылки или странные монтирования, то он уже не переносится. Поэтому утверждение о том, что pragma onceнельзя переносимо реализовать что-то, что по своей сути непереносимо (и не следует даже рассматривать), - это еще одна чушь перевернутого мира C ++.
doc

7
@JoseAntonioDuraOlmos Я согласен с тем, что символические ссылки - это функция ОС, которая выходит за рамки языка C ++. Следовательно, возникает вопрос, почему участники C ++ должны рассматривать то, что выходит за рамки языка? ИМО, пытаться гарантировать что-то, что не входит в их обязанности, не имеет никакого смысла. DOS поддерживает только 8 + 3 символа на имя файла, но никто не возражает, что #includeэто необходимо удалить, потому что директиву можно слепо неправильно использовать. #pragma onceникоим образом не ограничивает переносимость, при условии, что вы не будете использовать символические ссылки для нарушения компиляции.
doc

33

Раздел §16.6 Стандарта ( проект N3936 ) описывает #pragmaдирективы как:

Директива предварительной обработки формы

# pragma pp-tokensopt new-line

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

В основном #pragma onceэто конкретный экземпляр #pragmaдирективы для реализации, и нет, это не стандарт. Пока что.

Он часто широко поддерживается большинством «основных компиляторов», включая GCC и Clang, и поэтому иногда рекомендуется избегать использования шаблона include-guard.


10
Обратите внимание, что вы можете как #pragmaи #defineheader-guard.
Якк - Адам Неврамонт

19
«Любая прагма, не распознаваемая реализацией, игнорируется» . Означает ли это, что сообщение: Предупреждение: неопознанная директива прагмы не соответствует требованиям?
Родриго

6
«и поэтому это рекомендуемый способ избежать шаблона include-guard» - очень смелое заявление. Это нестандартный способ, и преимущества от его использования немногочисленны и вряд ли имеют отношение к моему опыту, поэтому мне пришлось убрать свой +1.
Alex

20
@Yakk: Если кто-то пишет #defineheader-guard, у него тоже нет причин писать #pragma once.
Наваз,

6
@Nawaz. Компилятор может хранить кеш каждого файла (по пути), который был #pragma onced, и в случае, если он #includeснова d, может пропустить #include(даже не открывать файл). gcc делает то же самое с защитой заголовков, но он очень и очень хрупкий. #pragmaОдин легко сделать, заголовок охранник один трудно.
Якк - Адам Неврамонт
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.