命名空间
变体
操作

实现定义行为控制

来自 cppreference.com

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

内容

[编辑] 语法

#pragma pragma_params (1)
_Pragma ( string-literal ) (2) (自 C99)
1) 以实现定义的方式运行(除非 pragma_params 是下面所示的标准编译指示之一)。
2)string-literal 中删除编码前缀(如果有)、外层引号和前导/尾随空格,将每个 \" 替换为 ",并将每个 \\ 替换为 \,然后对结果进行标记化(如 翻译阶段 3),然后将结果用作对 (1)#pragma 的输入。

[编辑] 解释

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

[编辑] 标准编译指示

以下三个编译指示由语言标准定义

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

其中 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

注意:不支持这些编译指示的编译器可能会提供等效的编译时选项,例如 gcc 的 -fcx-limited-range-ffp-contract

[编辑] 非标准编译指示

[编辑] #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 once,文件是根据其文件系统级别的标识来排除的,因此如果头文件在一个项目中存在于多个位置,则无法防止两次包含该头文件。

[编辑] #pragma pack

这组编译指示控制随后定义的结构和联合成员的最大对齐方式。

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

其中 arg 是一个小的 2 的幂,它指定以字节为单位的新对齐方式。

1) 将当前对齐方式设置为值 arg
2) 将当前对齐方式设置为默认值(由命令行选项指定)。
3) 将当前对齐方式的值推入内部堆栈。
4) 将当前对齐方式的值推入内部堆栈,然后将当前对齐方式设置为值 arg
5) 从内部堆栈中弹出顶部条目,然后将当前对齐方式设置为该值(恢复)。

#pragma pack 可能会减少结构的对齐方式,但它不能使结构过度对齐。

另请参阅有关 GCCMSVC 的具体细节。

[编辑] 参考

  • C17 标准 (ISO/IEC 9899:2018)
  • 6.10.6 编译指示指令 (p: 127)
  • 6.10.9 编译指示操作符 (p: 129)
  • C11 标准 (ISO/IEC 9899:2011)
  • 6.10.6 编译指示指令 (p: 174)
  • 6.10.9 编译指示操作符 (p: 178)
  • C99 标准 (ISO/IEC 9899:1999)
  • 6.10.6 编译指示指令 (p: 159)
  • 6.10.9 编译指示操作符 (p: 161-162)
  • C89/C90 标准 (ISO/IEC 9899:1990)
  • 3.8.6 编译指示指令

[编辑] 另请参阅

C++ 文档 关于 实现定义行为控制

[编辑] 外部链接

1.  Visual Studio 2019 中的 C++ 编译指示
2.  GCC 接受的编译指示
3.  各个编译指示描述IBM AIX XL C 16.1 中的标准编译指示
4.  附录 B. 编译指示 在 Sun Studio 11 C++ 用户指南中
5.  英特尔 C++ 编译器编译指示
6.  HP aCC 编译器编译指示