pragma once что такое

2.11 – Защита заголовков

Проблема повторяющегося определения

В уроке «2.6 – Предварительные объявления и определения» мы отметили, что идентификатор переменной или функции может иметь только одно определение (правило одного определения). Таким образом, программа, которая определяет идентификатор переменной более одного раза, вызовет ошибку компиляции:

Точно так же программы, которые определяют функцию более одного раза, также вызовут ошибку компиляции:

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

Рассмотрим следующий академический пример:

Таким образом, после разрешения всех директив #include файл main.cpp будет выглядеть так:

Защита заголовка

Хорошей новостью является то, что мы можем избежать указанной выше проблемы с помощью механизма, называемого защитой заголовка (или защитой включения). Защита заголовка – это директивы условной компиляции, которые имеют следующую форму:

Все ваши заголовочные файлы должны иметь защиту заголовков. Имя SOME_UNIQUE_NAME_HERE может быть любым, но по соглашению устанавливается равным полному имени заголовочного файла, набранному заглавными буквами, с использованием подчеркивания вместо пробелов и знаков препинания. Например, у square.h будет защита заголовка будет следующей:

Даже заголовочные файлы стандартной библиотеки используют защиту заголовков. Если бы вы взглянули на заголовочный файл iostream из Visual Studio, вы бы увидели:

Для продвинутых читателей

Обновление нашего предыдущего примера с помощью защиты заголовков

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

Как видно из примера, второе включение содержимого square.h (из geometry.h ) игнорируется потому, что SQUARE_H уже был определен при первом включении. Следовательно, функция getSquareSides включается только один раз.

Защита заголовков не препятствует одиночным включениям заголовка в разные файлы исходного кода.

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

Разве мы не можем просто избежать определений в файлах заголовков?

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

В будущем мы покажем вам довольно много случаев, когда в файл заголовка необходимо поместить определения, не являющиеся функциями. Например, C++ позволяет вам создавать свои собственные типы. Эти пользовательские типы обычно определяются в файлах заголовков, чтобы эти определения можно было распространить на исходные файлы, которые должны их использовать. Без защиты заголовков ваши исходные файлы могут иметь несколько идентичных копий этих определений, что приведет к ошибке компиляции повторяющихся определений.

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

#pragma once

Многие компиляторы поддерживают более простую альтернативную форму защиты заголовков с помощью директивы #pragma :

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

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

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

Резюме

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

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

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

Небольшой тест

Вопрос 1

Добавьте защиту заголовка в этот заголовочный файл:

Источник

Урок №23. Header guards и #pragma once

Обновл. 11 Сен 2021 |

На этом уроке мы рассмотрим, что такое header guards и #pragma once в языке C++, а также зачем они нужны и как их правильно использовать.

Проблема дублирования объявлений

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

То же самое касается и функций:

Рассмотрим следующую программу:

Эта, казалось бы, невинная программа, не скомпилируется! Проблема кроется в определении функции в файле math.h. Давайте детально рассмотрим, что здесь происходит:

Сначала main.cpp подключает заголовочный файл math.h, вследствие чего определение функции getSquareSides копируется в main.cpp.

Затем main.cpp подключает заголовочный файл geometry.h, который, в свою очередь, подключает math.h.

В geometry.h находится копия функции getSquareSides() (из файла math.h), которая уже во второй раз копируется в main.cpp.

Таким образом, после выполнения всех директив #include, main.cpp будет выглядеть следующим образом:

Мы получим дублирование определений и ошибку компиляции. Если рассматривать каждый файл по отдельности, то ошибок нет. Однако в main.cpp, который подключает сразу два заголовочных файла с одним и тем же определением функции, мы столкнемся с проблемами. Если для geometry.h нужна функция getSquareSides(), а для main.cpp нужен как geometry.h, так и math.h, то какое же решение?

Header guards

На самом деле решение простое — использовать header guards (защиту подключения в языке C++). Header guards — это директивы условной компиляции, которые состоят из следующего:

Источник

once pragma

Specifies that the compiler includes the header file only once, when compiling a source code file.

Syntax

Remarks

The use of #pragma once can reduce build times, as the compiler won’t open and read the file again after the first #include of the file in the translation unit. It’s called the multiple-include optimization. It has an effect similar to the include guard idiom, which uses preprocessor macro definitions to prevent multiple inclusions of the contents of the file. It also helps to prevent violations of the one definition rule: the requirement that all templates, types, functions, and objects have no more than one definition in your code.

We recommend the #pragma once directive for new code because it doesn’t pollute the global namespace with a preprocessor symbol. It requires less typing, it’s less distracting, and it can’t cause symbol collisions. Symbol collisions are errors caused when different header files use the same preprocessor symbol as the guard value. It isn’t part of the C++ Standard, but it’s implemented portably by several common compilers.

There’s no advantage to use of both the include guard idiom and #pragma once in the same file. The compiler recognizes the include guard idiom, and implements the multiple-include optimization the same way as the #pragma once directive if no non-comment code or preprocessor directive comes before or after the standard form of the idiom:

We recommend the include guard idiom when code must be portable to compilers that don’t implement the #pragma once directive, to maintain consistency with existing code, or when the multiple-include optimization is impossible. It can occur in complex projects when file system aliasing or aliased include paths prevent the compiler from identifying identical include files by canonical path.

Источник

Директивы pragma и __pragma _Pragma Ключевые слова и

Директивы директивы pragma определяют функции компилятора, зависящие от конкретного компьютера или операционной системы. __pragma Ключевое слово, относящееся только к компилятору Майкрософт, позволяет создавать pragma директивы кода внутри определений макросов. Стандартный _Pragma Оператор препроцессора появился в C99 и принят в c++ 11.

Синтаксис

** #pragma **Строка токена
** __pragma( **строка ) токена два подчеркивания в начале — конкретное расширение Майкрософт
** _Pragma( **строковый литерал ) C99

Remarks

Каждая реализация C и C++ поддерживает некоторые возможности, уникальные для хост-компьютера или операционной системы. Некоторые программы, например, должны выполнять точный контроль над расположением данных в памяти или управлять способом получения параметров определенными функциями. #pragma Директивы предлагают каждому компилятору возможность предоставлять функции для конкретного компьютера и операционной системы, сохраняя общую совместимость с языками C и C++.

Директивы директивы pragma зависят от конкретного компьютера или операционной системы и обычно отличаются для каждого компилятора. pragmaМожно использовать в условной директиве для предоставления новых функций препроцессора. Или используйте один из них, чтобы предоставить компилятору сведения, определяемые реализацией.

Компиляторы Microsoft C и C++ распознают следующие pragma директивы:

1 поддерживается только компилятором C++.

Директивы pragma и параметры компилятора

__pragma Ключевое слово

Компилятор также поддерживает __pragma ключевое слово Microsoft, которое имеет те же функциональные возможности, что и #pragma директива. Разница заключается в том, что __pragma ключевое слово можно использовать в качестве встроенного в определении макроса. #pragma Директива не может использоваться в определении макроса, так как компилятор интерпретирует символ решетки (#) в директиве как оператор строковый (#).

В следующем примере кода показано, как __pragma ключевое слово может использоваться в макросе. Этот код взят из заголовка мфкдуал. h в образце ACDUAL в «примеры поддержки компилятора COM»:

_Pragma Оператор предварительной обработки

Кавычки и обратные косые черты должны быть экранированы, как показано выше. pragmaСтрока, которая не распознана, игнорируется.

В следующем примере кода показано, как _Pragma ключевое слово можно использовать в макросе, похожем на утверждение. Он создает pragma директиву, которая подавляет предупреждение в случае, если условие выражения является константой.

Источник

What does #pragma once mean in C? [duplicate]

I saw the pragma many times,but always confused, anyone knows what it does?Is it windows only?

4 Answers 4

In the C and C++ programming languages, #pragma once is a non-standard but widely supported preprocessor directive designed to cause the current source file to be included only once in a single compilation. Thus, #pragma once serves the same purpose as #include guards, but with several advantages, including: less code, avoiding name clashes, and improved compile speed.

See the Wikipedia article for further details.

It’s used to replace the following preprocessor code:

A good convention is adding both to support legacy compilers (which is rare tho):

So if #pragma once fails the old method will still work.

Generally, the #pragma directives are intended for implementing compiler-specific preprocessor instructions. They are not standardized, so you shouldn’t rely on them too heavily.

In this case, #pragma once ‘s purpose is to replace the include guards that you use in header files to avoid multiple inclusion. It works a little faster on the compilers that support it, so it may reduce the compilation time on large projects with a lot of header files that are #include ‘ed frequently.

pragma is a directive to the preprocessor. It is usually used to provide some additional control during the compilation. For example do not include the same header file code. There is a lot of different directives. The answer depends on what follows the pragma word.

Not the answer you’re looking for? Browse other questions tagged c pragma or ask your own question.

Linked

Related

Hot Network Questions

site design / logo © 2021 Stack Exchange Inc; user contributions licensed under cc by-sa. rev 2021.11.12.40742

By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *