命名空间
变体
操作

实现定义的行为控制

来自 cppreference.cn
 
 
C++ 语言
 
 

实现定义的行为由 #pragma 指令控制。

目录

[编辑] 语法

#pragma pragma-params (1)
_Pragma( string-literal ) (2) (C++11 起)
1) 以实现定义的方式行为。
2)string-literal 中移除 L 前缀(如果有)、外层引号以及开头/结尾的空白字符,将每个 \" 替换为 ",将每个 \\ 替换为 \,然后对结果进行词法分析(如 翻译阶段 3),然后将结果用作 (1)#pragma 的输入。

[编辑] 解释

Pragma 指令控制编译器实现特定的行为,例如禁用编译器警告或更改对齐要求。任何未识别的 pragma 都会被忽略。

[编辑] 非标准 pragmas

ISO C++ 语言标准不要求编译器支持任何 pragmas。然而,多个实现支持一些非标准 pragmas

[编辑] #pragma STDC

ISO C 语言标准要求 C 编译器支持以下三个 pragmas,一些 C++ 编译器厂商在其 C++ 前端中不同程度地支持它们

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

其中 argONOFFDEFAULT

1) 如果设置为 ON,则通知编译器程序将访问或修改 浮点环境,这意味着禁止可能颠覆标志测试和模式更改的优化(例如,全局公共子表达式消除、代码移动和常量折叠)。默认值是实现定义的,通常是 OFF
2) 允许浮点表达式的*收缩*,即省略舍入误差和浮点异常的优化,这些误差和异常在表达式按原样求值时是可见的。例如,允许使用单个融合乘加 CPU 指令实现 (x * y) + z。默认值是实现定义的,通常是 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 的编译器可能会提供等效的编译时选项,例如 gcc 的 -fcx-limited-range-ffp-contract

[编辑] #pragma once

#pragma once 是一个非标准 pragma,受到绝大多数现代编译器的支持。如果它出现在头文件中,则表示它只会被解析一次,即使它在同一个源文件中被(直接或间接)包含多次。

防止多次包含同一头文件的标准方法是使用包含守卫

#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 使在多个文件中错误地使用相同宏名称成为不可能。另一方面,由于 #pragma once 是根据文件系统级别的身份排除文件的,因此如果头文件在项目中存在于多个位置,则无法防止多次包含。

[编辑] #pragma pack

这一系列 pragmas 控制后续定义的类和联合成员的最大对齐方式。

#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 可以减小类的对齐方式,但不能使类过度对齐。

另请参阅 GCCMSVC 的具体细节。

[编辑] 参考文献

  • C++23 标准 (ISO/IEC 14882:2024)
  • 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.  Visual Studio 中的 C++ pragmas
2.  GCC 接受的 Pragmas
3.  各个 pragma 描述IBM AIX XL C 16.1 中的标准 pragmas
4.  附录 B. Pragmas 在 Sun Studio 11 C++ 用户指南中
5.  Intel C++ 编译器 pragmas
6.  HP aCC A.06.25 的发布节点(包括 pragmas)