Spec-Zone.ru › C

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

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

Синтаксис

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

Объяснение

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

Стандартные директивы

Следующие три директивы определены стандартом языка:

#pragma STDC FENV_ACCESS arg(1)(с C99)
#pragma STDC FP_CONTRACT arg(2)(с C99)
#pragma STDC CX_LIMITED_RANGE arg(3)(с C99)

где arg это либо 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.

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

Нестандартные директивы

#pragma once

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

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

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

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

С #pragma once, тот же файл заголовка выглядит следующим образом

#pragma once
// contents of the header

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

#pragma pack

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

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

где arg это небольшая степень двойки и задаёт новое выравнивание в байтах.

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

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

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

Ссылки

  • Стандарт C17 (ISO/IEC 9899:2018):
    • 6.10.6 Директива pragma (с. 127)
    • 6.10.9 Оператор pragma (с. 129)
  • Стандарт C11 (ISO/IEC 9899:2011):
    • 6.10.6 Директива pragma (с. 174)
    • 6.10.9 Оператор pragma (с. 178)
  • Стандарт C99 (ISO/IEC 9899:1999):
    • 6.10.6 Директива pragma (с. 159)
    • 6.10.9 Оператор pragma (с. 161-162)
  • Стандарт C89/C90 (ISO/IEC 9899:1990):
    • 3.8.6 Директива pragma

См. также

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

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

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

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

Spec-Zone.ru

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