Namespaces
Variants

Implementation defined behavior control

From cppreference.net

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

目录

语法

#pragma 编译指示参数 (1)
_Pragma ( 字符串字面量 ) (2) (自 C99 起)
1) 以实现定义的方式行为(除非 pragma_params 是下列标准杂注之一)。
2) 移除 字符串字面量 的编码前缀(如果存在)、外层引号及首尾空白字符,将每个 \" 替换为 " 、每个 \\ 替换为 \ ,随后对结果进行词法分析(如同在 翻译阶段3 中),最终将结果作为 #pragma 的输入,处理方式同 (1)

说明

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

标准杂注

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

#pragma STDC FENV_ACCESS 参数 (1) (C99起)
#pragma STDC FP_CONTRACT 参数 (2) (C99起)
#pragma STDC CX_LIMITED_RANGE 参数 (3) (C99起)

其中 arg 可以是 ON OFF DEFAULT

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)]/(u 2
+v 2
)
以及 |x+iy| = x 2
+y 2
,即使可能存在中间结果溢出。换言之,程序员需确保传递给这些函数的数值范围是受限的。默认值为 OFF

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

非标准杂注

#pragma once

#pragma once 是一种非标准预处理指令,受到 绝大多数现代编译器 的支持。当它出现在头文件中时,表示该文件即使(直接或间接地)在同一源文件中被多次包含,也仅会被解析一次。

防止同一头文件被多次包含的标准方法是使用 包含保护

#ifndef LIBRARY_FILENAME_H
#define LIBRARY_FILENAME_H
// 头文件内容
#endif /* LIBRARY_FILENAME_H */

这样,除了翻译单元中头文件的首次包含外,所有后续包含都会被排除在编译之外。所有现代编译器都会记录头文件使用了包含保护这一事实,只要保护宏仍处于定义状态,当再次遇到该文件时就不会重新解析(参见例如 gcc 文档)。

使用 #pragma once 时,相同的头文件显示为

#pragma once
// 头文件内容

与头文件保护符不同, #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 可能会降低结构体的对齐方式,但无法使结构体过度对齐。

另请参阅针对 GCC MSVC 的具体细节。

参考文献

  • C23 标准 (ISO/IEC 9899:2024):
  • 6.10.6 Pragma 指令 (p: TBD)
  • 6.10.9 Pragma 运算符 (p: TBD)
  • C17 标准 (ISO/IEC 9899:2018):
  • 6.10.6 Pragma 指令 (页: 127)
  • 6.10.9 Pragma 运算符 (页: 129)
  • C11 标准 (ISO/IEC 9899:2011):
  • 6.10.6 Pragma 指令 (p: 174)
  • 6.10.9 Pragma 运算符 (p: 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++ documentation for Implementation defined behavior control

外部链接

1. Visual Studio 中的 C++ 杂注
2. GCC 接受的 杂注
3. IBM AIX XL C 16.1 中的 单个杂注说明 标准杂注
4. Sun Studio 11 C++ 用户指南中的 附录 B. 杂注
5. Intel C++ 编译器杂注
6. HP aCC 编译器杂注