#pragma是否曾经是C ++ 11标准的一部分?


140

传统上,避免C ++中包含多个标头的标准且可移植的方法是使用#ifndef - #define - #endif预编译器指令方案,该方案也称为宏保护方案(请参见下面的代码段)。

#ifndef MY_HEADER_HPP
#define MY_HEADER_HPP
...
#endif

但是,在大多数实现/编译器中(请参见下图),还有一个更“优雅”的替代方案,其作用与称为的宏保护方案相同#pragma once#pragma once与宏保护方案相比,它具有多个优点,包括更少的代码,避免名称冲突以及有时提高了编译速度。

在此处输入图片说明

经过研究,我意识到尽管#pragma once几乎所有已知的编译器都支持伪指令,但是伪#pragma once指令是否属于C ++ 11标准还是有一定的困惑。

问题:

  • 有人可以澄清#pragma once指令是否属于C ++ 11标准吗?
  • 如果它不是C ++ 11标准的一部分,是否有任何计划将其包含在更高版本中(例如C ++ 14或更高版本)?
  • 如果有人可以进一步详细说明使用这两种技术中的任何一种(例如,宏观卫士与#pragma once)的优势/劣势,那也很好。

9
顺便说一句,该标准禁止将双下划线用作标头保护符,该规范为实现保留所有以双下划线开头的符号(其他符号除外)。
Matteo Italia

9
也禁止使用前划线和大写字母。第二,浑浊在哪里?我只是看到编译器支持,没有人声称它是标准的一部分?
Yakk-Adam Nevraumont 2014年

1
对于第三个要点,请看一个相关的问题:#pragma曾经是一个安全的包括门卫吗?在这种情况下,标头警卫工作了,但#pragma once通常不起作用。
user1942027

1
可能的重复之处在于它回答了这个问题,而没有提及C ++ 11。
Yakk-Adam Nevraumont 2014年

3
嗯,它没有在任何正式文档中编码,但是您可以将其视为事实上的标准。
任思远2014年

Answers:


107

#pragma once不是标准。这是一个广泛的(但不是通用的)扩展,可以使用

  • 如果您的便携性问题有限,并且
  • 您可以确保所有包含文件始终位于本地磁盘上。

考虑将其标准化,但由于无法可靠实施而被拒绝。(当您具有可通过几个不同的远程安装访问的文件时,就会出现问题。)

确保在单个开发中不存在包含卫队冲突是相当容易的。对于可能由许多不同的开发人员使用的库,显而易见的解决方案是在创建库时为include保护生成许多随机字符。(可以设置一个好的编辑器来为您执行此操作,只要您打开新的标头即可。)但是即使没有此操作,我仍然没有遇到库之间冲突的任何问题。


11
不只是远程安装。硬链接,软链接,基本构造(在Windows上)。可能会变得非常混乱。
托尼2014年

45
为什么编译器不能使用SHA-1或MD5校验和来标识文件?
谢尔盖(Sergey)2015年

29
如果每个主要编译器都支持,我真的不认为不将某些内容放入标准中是没有意义的。实际上,标准中所支持的东西远少于此。同样,当我们谈论包含文件时,抱怨边缘问题似乎很愚蠢,其中文件名冲突已经是一个大问题。如果对#included头文件的概念普遍应用了对100%无问题功能的要求,那就太好了。
TED

38
如果您的代码通过符号链接或怪异的装载文件包含了来自不同位置的某些文件,则该文件已不可移植。因此,争论pragma once不能移植实现某些本来就不可移植的东西(甚至不应该考虑)是C ++颠倒世界的又一废话。
doc

7
@JoseAntonioDuraOlmos我同意符号链接是一种操作系统功能,超出了C ++语言的范围。因此出现了一个问题,为什么C ++委员应该考虑超出语言范围的内容?试图保证某些事情不是他们的责任,IMO毫无意义。DOS每个文件名仅支持8 + 3个字符,但是没有人认为#include必须删除它,因为一个人可以盲目地滥用该指令。#pragma once不会以任何方式限制可移植性,前提是您不会利用符号链接来破坏编译。
doc

32

该标准的第16.6节(N3936草案)将#pragma指令描述为:

形式的预处理指令

# pragma pp-tokensopt new-line

使实现以实现定义的方式运行。该行为可能导致翻译失败或导致翻译器或生成的程序以不符合标准的方式运行。该实现无法识别的任何杂注将被忽略。

基本上,它#pragma once#pragma指令的特定于实现的实例,不,它不是标准的。然而。

它通常受到包括GCCClang在内的大多数“主要编译器”的广泛支持,因此有时建议避免使用包含保护的样板。


10
请注意,您既可以#pragma#define头后卫。
Yakk-Adam Nevraumont 2014年

18
“将忽略该实现无法识别的任何杂注”。这是否表示以下消息:警告:无法识别的编译指示不符合要求?
rodrigo 2014年

6
“因此建议避免使用包含保护的样板”(这是非常大胆的声明)。这是一种非标准的方式,使用它的好处很少,而且与我的经验几乎没有关系,因此我不得不取消+1。
Alex

19
@Yakk:如果有人写#define标题保护,则他/她也没有理由写#pragma once
纳瓦兹2014年

5
@Nawaz编译器可以保留已#pragma onced 的每个文件的缓存(按路径),如果#include再次被d则可以跳过#include(甚至不打开文件)。 gcc对于标头后卫也一样,但是非常脆弱。在#pragma一个很容易做的,头一个后卫很难。
Yakk-Adam Nevraumont 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.