Я читал, что существует некоторая оптимизация компилятора при использовании, #pragma once
которая может привести к более быстрой компиляции. Я признаю, что это нестандартно и, следовательно, может создать проблему кросс-платформенной совместимости.
Это то, что поддерживается большинством современных компиляторов на не-Windows платформах (gcc)?
Я хочу избежать проблем с компиляцией платформы, но также хочу избежать дополнительной работы защитников:
#pragma once
#ifndef HEADER_H
#define HEADER_H
...
#endif // HEADER_H
Должен ли я быть обеспокоен? Должен ли я потратить еще какую-нибудь умственную энергию на это?
c++
include-guards
Райан Эмерл
источник
источник
#pragma once
в VS 2008 , похоже, избегаются некоторые проблемы с представлением классов. Я нахожусь в процессе избавления от включенных защит и включения их замены#pragma once
по этой причине.Ответы:
Использование
#pragma once
должно работать на любом современном компиляторе, но я не вижу причин, чтобы не использовать стандартный#ifndef
include guard. Работает просто отлично. Единственное предостережение в том, что GCC не поддерживал#pragma once
до версии 3.4 .Я также обнаружил, что, по крайней мере в GCC, он распознает стандартную
#ifndef
защиту include и оптимизирует его , поэтому он не должен быть намного медленнее, чем#pragma once
.источник
#pragma once
обычно быстрее, потому что файл не подвергается предварительной обработке.ifndef/define/endif
В любом случае требуется предварительная обработка, потому что после этого блока вы можете получить что-то компилируемое (теоретически)#ifndef FOO_BAR_H
элементов существует дополнительное требование, согласно которому вы должны определить новый символ, например , обычно для файла, такого как "foo_bar.h". Если вы позже переименуете этот файл, следует ли вам соответствующим образом настроить защиту для включения в соответствии с этим соглашением? Кроме того, если у вас есть два разных файла foo_bar.h в двух разных местах в вашем кодовом дереве, вы должны подумать о двух разных символах для каждого. Короткий ответ - использовать,#pragma once
и если вам действительно нужно скомпилировать в среде, которая его не поддерживает, тогда добавьте защитные ключи для этой среды.#pragma once
у него есть один недостаток (кроме нестандартного), и это если у вас один и тот же файл в разных местах (у нас это есть, потому что наша система сборки копирует файлы), тогда компилятор будет думать, что это разные файлы.источник
#ifdef
значение макроса также может отличаться.Я бы хотел
#pragma once
(или что-то подобное) было в стандарте. Включить охранников не так уж и сложно (но их, кажется, немного сложно объяснить людям, изучающим язык), но это кажется незначительным раздражением, которого можно было бы избежать.Фактически, поскольку в 99,98% случаев такое
#pragma once
поведение является желаемым, было бы неплохо, если бы компилятор автоматически предотвращал многократное включение заголовка,#pragma
включая или что-то, что допускает двойное включение.Но у нас есть то, что у нас есть (кроме того, что у вас может не быть
#pragma once
).источник
#import
директива.Я не знаю о каких-либо преимуществах производительности, но это, безусловно, работает. Я использую его во всех своих проектах C ++ (если я использую компилятор MS). Я считаю, что это более эффективно, чем использование
Он выполняет ту же работу и не заполняет препроцессор дополнительными макросами.
GCC поддерживает
#pragma once
официально начиная с версии 3.4 .источник
GCC поддерживает
#pragma once
начиная с 3.4, см. Http://en.wikipedia.org/wiki/Pragma_once для дальнейшей поддержки компилятора.Большой плюс, который я вижу в использовании
#pragma once
защиты от включения защиты, заключается в том, чтобы избежать ошибок копирования / вставки.Посмотрим правде в глаза: большинство из нас едва ли начинают новый заголовочный файл с нуля, а просто копируют существующий и модифицируют его в соответствии с нашими потребностями. Намного проще создать рабочий шаблон, используя
#pragma once
вместо включаемых охранников. Чем меньше мне нужно изменить шаблон, тем меньше вероятность возникновения ошибок. Наличие одного и того же встроенного средства защиты в разных файлах приводит к странным ошибкам компилятора, и требуется некоторое время, чтобы выяснить, что пошло не так.TL; DR:
#pragma once
проще в использовании.источник
Я использую его, и я доволен им, поскольку мне приходится печатать намного меньше, чтобы создать новый заголовок. У меня это работало нормально на трех платформах: Windows, Mac и Linux.
У меня нет никакой информации о производительности, но я считаю, что разница между #pragma и include guard не будет ничем по сравнению с медлительностью синтаксического анализа грамматики C ++. Это настоящая проблема. Попробуйте скомпилировать такое же количество файлов и строк с помощью компилятора C #, например, чтобы увидеть разницу.
В конце концов, использование охраны или прагмы не будет иметь никакого значения.
источник
Использование '
#pragma once
' может не иметь никакого эффекта (оно не поддерживается повсеместно - хотя оно все шире поддерживается), поэтому вам все равно нужно использовать код условной компиляции, в этом случае зачем использовать '#pragma once
'? Компилятор, вероятно, все равно его оптимизирует. Это зависит от вашей целевой платформы, хотя. Если все ваши цели поддерживают это, тогда продолжайте и используйте это - но это должно быть сознательное решение, потому что весь ад развалится, если вы только используете прагму, а затем портируете на компилятор, который не поддерживает его.источник
Преимущество в производительности заключается в том, что нет необходимости открывать файл после прочтения #pragma. С защитой, компилятор должен открыть файл (который может быть дорогостоящим по времени), чтобы получить информацию, что он не должен снова включать его содержимое.
Это теория только потому, что некоторые компиляторы автоматически не открывают файлы, в которых не было никакого кода для чтения, для каждой единицы компиляции.
В любом случае, это относится не ко всем компиляторам, поэтому в идеале нужно избегать использования #pragma, поскольку кросс-платформенный код вообще не является стандартным / не имеет стандартизированного определения и эффекта. Однако, на самом деле, это действительно лучше, чем охранники.
В конце концов, лучшее предложение, которое вы можете получить, чтобы быть уверенным в том, что ваш компилятор будет иметь лучшую скорость без необходимости проверять поведение каждого компилятора в этом случае, это использовать как pragma один раз, так и guard.
Таким образом вы получаете лучшее из обоих (кроссплатформенность и скорость компиляции справки).
Поскольку печатание дольше, я лично использую инструмент, который помогает генерировать все это очень хитрым способом (Visual Assist X).
источник
pragma
послеifndef
? Есть ли выгода?Не всегда.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52566 содержит хороший пример двух файлов, которые должны быть включены в оба, но ошибочно считаются идентичными из-за идентичных меток времени и содержимого (не идентичное имя файла) ,
источник
#pragma once
является нестандартным, поэтому все, что компилятор решит сделать, будет «правильным». Конечно, тогда мы можем начать говорить о том, что «ожидается», а что «полезно».Использование gcc 3.4 и 4.1 на очень больших деревьях (иногда использование distcc ), мне еще предстоит увидеть какое-либо ускорение при использовании #pragma вместо или в сочетании со стандартными средствами защиты include.
Я действительно не понимаю, как это может сбить с толку старые версии gcc или даже других компиляторов, поскольку реальной экономии нет. Я не пробовал все разные де-линтеры, но готов поспорить, что это многих их запутает.
Я тоже хотел бы, чтобы он был принят на ранней стадии, но я вижу аргумент «Зачем нам это нужно, если ifndef работает отлично?». Учитывая много темных углов и сложностей С, включить охранников - это одна из самых простых и понятных вещей. Если у вас есть хотя бы небольшие знания о том, как работает препроцессор, они должны быть понятны.
Если вы заметили значительное ускорение, обновите свой вопрос.
источник
В наши дни охранники старой школы так же быстры, как и #pragma. Даже если компилятор не обрабатывает их специально, он все равно остановится, когда увидит #ifndef WHATEVER и WHATEVER. Открытие файла сегодня очень дешево. Даже если бы было улучшение, это было бы порядка миллисекунд.
Я просто не использую #pragma один раз, так как это не приносит никакой пользы. Чтобы избежать столкновения с другими включенными охранниками, я использую что-то вроде: CI_APP_MODULE_FILE_H -> CI = Company Initials; APP = название приложения; остальное говорит само за себя.
источник
Основным отличием является то, что компилятору пришлось открыть файл заголовка, чтобы прочитать include guard. Для сравнения, однажды прагма заставляет компилятор отслеживать файл и не выполнять какой-либо ввод-вывод файла, когда он сталкивается с другим включением для того же файла. Хотя это может показаться незначительным, оно может легко масштабироваться с огромными проектами, особенно без хорошего заголовка, включая дисциплины.
Тем не менее, в наши дни компиляторы (включая GCC) достаточно умны, чтобы когда-то относиться к таким элементам защиты, как прагма. то есть они не открывают файл и избегают штрафа ввода-вывода файла.
В компиляторах, которые не поддерживают прагму, я видел ручные реализации, которые немного громоздки ..
Лично мне нравится подход #pragma Once, так как он позволяет избежать проблем с именами коллизий и потенциальных ошибок опечаток. Это также более элегантный код для сравнения. Тем не менее, для переносимого кода не должно быть вреда иметь оба, если компилятор не жалуется на это.
источник
#pragma once
существовало!Если мы используем msvc или Qt (до Qt 4.5), так как GCC (до 3.4), msvc оба поддерживают
#pragma once
, я не вижу причин, чтобы не использовать#pragma once
.Имя исходного файла обычно совпадает с именем класса, и мы знаем, что когда-нибудь нам понадобится рефакторинг , чтобы переименовать имя класса, тогда нам пришлось изменить
#include XXXX
также, так что я думаю, что ручное обслуживание#include xxxxx
не является умной работой. даже с расширением Visual Assist X поддерживать «xxxx» не обязательно.источник
Дополнительное примечание для людей, думающих, что автоматическое одноразовое включение заголовочных файлов всегда желательно: я строю генераторы кода, использующие двойное или множественное включение заголовочных файлов с десятилетий. Специально для создания заглушек библиотеки протоколов мне очень удобно иметь чрезвычайно портативный и мощный генератор кода без дополнительных инструментов и языков. Я не единственный разработчик, использующий эту схему, как показывают эти блоги X-Macros . Это не было бы возможно сделать без отсутствующей автоматической охраны.
источник
X-Macro
функции, но это не основное использование include, разве это не должно быть наоборот, как header unguard / # pragma multi, если мы будем придерживаться DRY?