Spec-Zone.ru › C++

Управление поведением, определённым реализацией

Поведение, определённое реализацией, контролируется директивой #pragma.

Синтаксис

#pragma pragma-params (1)
_Pragma( строковая_литераль ) (2) (с C++11)
1) Ведёт себя в соответствии с поведением, определённым реализацией.
2) Удаляет префикс L (если он есть), внешние кавычки и начальные/конечные пробелы из строковая_литераль, заменяет каждый \" на " и каждый \\ на \, затем токенизирует результат (как в фазе трансляции 3), а затем использует результат как вход для #pragma в (1).

Объяснение

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

Нестандартные pragmas

Стандарт языка C++ ISO не требует от компиляторов поддержки каких-либо pragmas. Однако несколько нестандартных pragmas поддерживаются множеством реализаций:

#pragma STDC

Стандарт языка C ISO требует, чтобы компиляторы C поддерживали следующие три pragmas, а некоторые поставщики компиляторов C++ поддерживают их в своих фронтендах для C++ в различной степени:

#pragma STDC FENV_ACCESS аргумент (1)
#pragma STDC FP_CONTRACT аргумент (2)
#pragma STDC CX_LIMITED_RANGE аргумент (3)

где аргумент может быть ON, OFF, или DEFAULT.

1) Если установлено в значение ON, сообщает компилятору, что программа будет обращаться к среде с плавающей точкой или изменять её, что означает, что оптимизации, которые могут нарушить проверки флагов и изменения режимов (например, глобальная элиминация общих подвыражений, перемещение кода и свёртка констант) запрещены. Значение по умолчанию зависит от реализации, обычно OFF.
2) Разрешает сжатие выражений с плавающей точкой, то есть оптимизации, которые пропускают округления и исключения с плавающей точкой, которые были бы замечены, если бы выражение оценивалось точно так, как написано. Например, позволяет реализовать (x * y) + z с помощью одной инструкции процессора fused multiply-add. Значение по умолчанию зависит от реализации, обычно ON.
3) Сообщает компилятору, что умножение, деление и вычисление абсолютного значения комплексных чисел могут использовать упрощённые математические формулы (x+iy)×(u+iv) = (xu-yv)+i(yu+xv), (x+iy)/(u+iv) = [(xu+yv)+i(yu-xv)]/(u2+v2), и |x+iy| = √x2+y2, несмотря на возможность промежуточного переполнения. Другими словами, программист гарантирует, что диапазон значений, которые будут переданы в эти функции, ограничен. Значение по умолчанию — OFF.

Поведение программы неопределено, если любая из трёх pragmas выше появляется в любом контексте, кроме как вне всех внешних деклараций или перед всеми явными декларациями и операторами внутри составного оператора.

Примечание: компиляторы, которые не поддерживают эти pragmas, могут предоставить эквивалентные параметры времени компиляции, такие как -fcx-limited-range и -ffp-contract gcc.

#pragma once

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

Стандартный подход к предотвращению многократного включения одного и того же заголовка — использование include guard:

#ifndef LIBRARY_FILENAME_H
#define LIBRARY_FILENAME_H
// contents of the header
#endif /* LIBRARY_FILENAME_H */

Чтобы все, кроме первого включения заголовка в любой единице трансляции, были исключены из компиляции. Все современные компиляторы записывают тот факт, что файл заголовка использует include guard, и не перекомпилируют файл, если он встречается снова, при условии, что guard всё ещё определён (см., например, gcc).

С #pragma once, тот же самый заголовок выглядит как

#pragma once
// contents of the header

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

#pragma pack

Эта группа директив pragma контролирует максимальное выравнивание для последующих членов класса и объединения.

#pragma pack(arg) (1)
#pragma pack() (2)
#pragma pack(push) (3)
#pragma pack(push, arg) (4)
#pragma pack(pop) (5)

где аргумент — это малая степень двойки и определяет новое выравнивание в байтах.

1) Устанавливает текущее выравнивание в значение аргумент.
2) Устанавливает текущее выравнивание в значение по умолчанию (определённое параметром командной строки).
3) Помещает значение текущего выравнивания в внутренний стек.
4) Помещает значение текущего выравнивания в внутренний стек, а затем устанавливает текущее выравнивание в значение аргумент.
5) Выталкивает верхний элемент из внутреннего стека, а затем устанавливает (восстанавливает) текущее выравнивание в это значение.

#pragma pack может уменьшить выравнивание класса, но не может сделать класс слишком выровненным.

См. также подробные сведения для GCC и MSVC.

Ссылки

  • Стандарт C++23 (ISO/IEC 14882:2023):
    • 15.9 Директива pragma [cpp.pragma]
  • Стандарт C++20 (ISO/IEC 14882:2020):
    • 15.9 Директива pragma [cpp.pragma]
  • Стандарт C++17 (ISO/IEC 14882:2017):
    • 19.6 Директива pragma [cpp.pragma]
  • Стандарт C++14 (ISO/IEC 14882:2014):
    • 16.6 Директива pragma [cpp.pragma]
  • Стандарт C++11 (ISO/IEC 14882:2011):
    • 16.6 Директива pragma [cpp.pragma]
  • Стандарт C++98 (ISO/IEC 14882:1998):
    • 16.6 Директива pragma [cpp.pragma]

См. также

Документация по C для Управление поведением, определённым реализацией

Внешние ссылки

1. Директивы pragma в Visual Studio
2. Директивы pragma, принятые GCC
3. Описание отдельных pragmas и Стандартные pragmas в IBM AIX XL C 16.1
4. Приложение B. Директивы pragma в руководстве пользователя Sun Studio 11 C++
5. Директивы pragma Intel C++ компилятора
6. Ноды выпуска (включают pragmas) для HP aCC A.06.25

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/preprocessor/impl

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API