Подтвердить что ты не робот

Является ли # прагма когда-то безопасным включать охрану?

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

Это что-то, что поддерживается большинством современных компиляторов на платформах без windows (gcc)?

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

#pragma once
#ifndef HEADER_H
#define HEADER_H

...

#endif // HEADER_H

Должен ли я быть обеспокоен? Должен ли я расходовать на это дополнительную психическую энергию?

4b9b3361

Ответ 1

Использование #pragma once должно работать на любом современном компиляторе, но я не вижу никаких причин не использовать стандартный #ifndef include guard. Работает просто отлично. Единственное предостережение: GCC не поддерживал #pragma once до версии 3.4.

Я также обнаружил, что по крайней мере в GCC он распознает стандарт #ifndef include guard и оптимизирует его, поэтому он не должен быть намного медленнее, чем #pragma once.

Ответ 2

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

Ответ 3

Желаю #pragma once (или что-то в этом роде) быть в стандарте. Включить стражи - это не очень большое дело (но они кажутся немного трудными для объяснения людям, изучающим язык), но это кажется незначительным раздражением, которого можно было бы избежать.

Фактически, с 99,98% времени поведение #pragma once является желаемым поведением, было бы неплохо, если бы предотвращение множественного включения заголовка автоматически обрабатывалось компилятором с помощью #pragma или что-то вроде разрешить двойное включение.

Но у нас есть то, что у нас есть (за исключением того, что у вас может не быть #pragma once).

Ответ 4

Я не знаю никаких преимуществ по производительности, но это, безусловно, работает. Я использую его во всех моих проектах на С++ (если я использую компилятор MS). Я считаю, что это более эффективно, чем использование

#ifndef HEADERNAME_H
#define HEADERNAME_H
...
#endif

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

GCC поддерживает #pragma once официально начиная с версии 3.4.

Ответ 5

GCC поддерживает #pragma once с 3.4, см. http://en.wikipedia.org/wiki/Pragma_once для дальнейшей поддержки компилятора.

Большой потенциал роста, который я вижу при использовании #pragma once, в отличие от включения охранников, заключается в том, чтобы избежать ошибок копирования/вставки.

Посмотрим правде в глаза: большинство из нас вряд ли начнут новый заголовок с нуля, а просто скопируют существующий и модифицируют его в соответствии с нашими потребностями. Создавать рабочий шаблон с помощью #pragma once гораздо проще, чем включать защитные устройства. Чем меньше я должен изменить шаблон, тем меньше я могу столкнуться с ошибками. Наличие того же, что и охранник в разных файлах, приводит к странным ошибкам компилятора, и требуется некоторое время, чтобы выяснить, что пошло не так.

TL; DR: #pragma once проще в использовании.

Ответ 6

Использование '#pragma once' может не иметь никакого эффекта (оно не поддерживается повсеместно - хотя оно все чаще поддерживается), поэтому вам нужно использовать условный код компиляции в любом случае, и в этом случае зачем беспокоиться о '#pragma once '? Компилятор, вероятно, оптимизирует его. Однако это зависит от ваших целевых платформ. Если все ваши цели поддерживают его, тогда идите и используйте его, но это должно быть сознательное решение, потому что все ад будет разрываться, если вы используете только прагму, а затем порт для компилятора, который его не поддерживает.

Ответ 7

Я использую его, и я доволен этим, поскольку мне приходится вводить гораздо меньше, чтобы создать новый заголовок. Он отлично работал у меня на трех платформах: Windows, Mac и Linux.

У меня нет информации о производительности, но я считаю, что разница между #pragma и включенным защитником будет ничем не отличаться от медленности разбора грамматики С++. Это настоящая проблема. Попробуйте собрать такое же количество файлов и строк с помощью компилятора С#, например, чтобы увидеть разницу.

В конце концов, используя охрану или прагму, не имеет значения вообще.

Ответ 8

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

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

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

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

#ifndef NR_TEST_H
#define NR_TEST_H
#pragma once

#include "Thing.h"

namespace MyApp
{
 // ...
}

#endif

Таким образом, вы получаете лучшее из обоих (кроссплатформенность и скорость компиляции справки).

Поскольку он дольше печатается, я лично использую инструмент, который помогает генерировать все это очень хитрым способом (Visual Assist X).

Ответ 9

Не всегда.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52566  содержит хороший пример двух файлов, которые должны быть включены в оба, но ошибочно считаются идентичными из-за идентичных временных меток и содержимого (не идентичного имени файла).

Ответ 10

Используя gcc 3.4 и 4.1 на очень больших деревьях (иногда используя distcc), мне еще предстоит увидеть скорость при использовании #pragma один раз вместо или в сочетании со стандартными включенными защитными устройствами.

Я действительно не вижу, как это может потенциально запутать более старые версии gcc или даже других компиляторов, поскольку нет реальной экономии. Я не пробовал все различные делинтеры, но я готов поспорить, что это смутит многих из них.

Я тоже хочу, чтобы он был принят на ранней стадии, но я вижу аргумент "Зачем нам это нужно, когда ifndef работает отлично?". Учитывая C много темных углов и сложностей, включите охранники - одна из самых простых, объясняющих себя вещей. Если у вас есть небольшое представление о том, как работает препроцессор, они должны быть понятны.

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

Ответ 11

Сегодня в старую школу входят охранники так же быстро, как и # прагма. Даже если компилятор не относится к ним специально, он все равно остановится, когда он увидит, что определено #ifndef WHATEVER и WHATEVER. Открытие файла сегодня грязно. Даже если бы было улучшение, это было бы порядка миллисекундов.

Я просто просто не использую #pragma один раз, так как он не имеет никакой пользы. Чтобы избежать столкновения с другими включенными охранниками, я использую что-то вроде: CI_APP_MODULE_FILE_H → CI = инициалы компании; APP = название приложения; остальное самоочевидно.

Ответ 12

Основное отличие заключается в том, что компилятор должен был открыть файл заголовка, чтобы прочитать защитный код include. Для сравнения, прагма однажды заставляет компилятор отслеживать файл и не делать ни одного файла IO, когда он встречается с другим, для одного и того же файла. Хотя это может показаться незначительным, оно может легко масштабироваться с помощью огромных проектов, особенно без хорошего заголовка, включая дисциплины.

Тем не менее, в наши дни компиляторы (включая GCC) достаточно умны, чтобы лечить включенные охранники, такие как прагма один раз. то есть они не открывают файл и не предотвращают штраф IO файла.

В компиляторах, которые не поддерживают прагму, я видел ручные реализации, которые немного громоздки.

#ifdef FOO_H
#include "foo.h"
#endif

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

Ответ 13

Если мы используем msvc или Qt (до Qt 4.5), так как GCC (до 3.4), msvc поддерживают #pragma once, я не вижу причин не использовать #pragma once.

Имя исходного файла обычно совпадает с одинаковым именем класса, и мы знаем, что когда-то нам нужен рефакторинг, чтобы переименовать имя класса, тогда нам также пришлось изменить #include XXXX, поэтому я считаю, что руководство поддерживает #include xxxxx, не является умным Работа. даже с расширением Visual Assist X, поддержка "xxxx" не является необходимой работой.

Ответ 14

Дополнительное примечание для людей, думающих, что всегда требуется автоматическое однократное включение заголовочных файлов: я создаю генераторы кода, используя двойные или множественные включения файлов заголовков с десятилетий. Специально для создания ящиков библиотеки протоколов мне очень удобно иметь чрезвычайно портативный и мощный генератор кода без каких-либо дополнительных инструментов и языков. Я не единственный разработчик, использующий эту схему в качестве этого блога X-Macros. Это было бы невозможно обойтись без отсутствующей автоматической защиты.