使用一次pragma有什么危险? 现代C和C++编译器支持非标准·γ-语用学曾经的,预处理器指令,其类似于经典的头保护: #ifndef hopefully_unique_identifier_that_doesnt_hurt_the_code #define hopefully_unique_identifier_that_doesnt_hurt_the_code // some code here #endif

使用一次pragma有什么危险? 现代C和C++编译器支持非标准·γ-语用学曾经的,预处理器指令,其类似于经典的头保护: #ifndef hopefully_unique_identifier_that_doesnt_hurt_the_code #define hopefully_unique_identifier_that_doesnt_hurt_the_code // some code here #endif,c++,c,macros,C++,C,Macros,我知道,经典方法的一个问题是,一旦包含了一个头,就必须#undf头保护宏才能再次包含它(对我来说,这样做是一种主要的代码味道,但这不是重点)。同样的问题也出现在#pragma once方法中,但不允许多次包含标题 经典方法的另一个问题是,您可能会意外地在不相关的位置定义同一个宏,因此可能未按预期包含标头,或者执行一些我无法想象的其他讨厌的操作。这在实践中是相当容易避免的,通过遵守某些约定,例如将宏基于类似UUID的对象(即随机字符串)或(不太理想的方法),基于文件名,它们在中定义 在现实生活中,

我知道,经典方法的一个问题是,一旦包含了一个头,就必须
#undf
头保护宏才能再次包含它(对我来说,这样做是一种主要的代码味道,但这不是重点)。同样的问题也出现在
#pragma once
方法中,但不允许多次包含标题

经典方法的另一个问题是,您可能会意外地在不相关的位置定义同一个宏,因此可能未按预期包含标头,或者执行一些我无法想象的其他讨厌的操作。这在实践中是相当容易避免的,通过遵守某些约定,例如将宏基于类似UUID的对象(即随机字符串)或(不太理想的方法),基于文件名,它们在中定义

在现实生活中,我很少经历过这些潜在的问题,所以我并不认为它们是主要的问题。

我能想到的关于
#pragma once
的唯一潜在现实问题是,它不是一个标准的东西——你所依赖的东西可能不是无处不在的,即使它在实践中无处不在(*)

那么,除了我已经提到的那些问题外,
#pragma once
还有哪些潜在问题?我是否太相信在实践中,在任何地方都可以使用它


(*)一些只有少数人使用的次要编译器被排除在外。

到目前为止,我已经使用了一套不错的编译器:

  • 海湾合作委员会
  • 叮当声/LLVM
  • IBM XLC
  • <>英特尔C++编译器
唯一不支持
#pragma once
的编译器是IBM XLC编译器,它甚至不支持C++11,所以我不感兴趣。如果需要在Blue Gene/Q上使用IBM XLC编译器,则不能一次性使用
#pragma

很久以前,某些编译器不理解include-guard习惯用法,会反复打开头文件,结果发现预处理器将内容缩减为零。有了这些编译器,只需使用一次
#pragma
就可以获得编译时的好处。然而,这已经在主要的编译器中实现了,因此这在当今没有什么不同

也许你有一些特殊的编译器为你的嵌入式系统。那个人可能一次都不能使用
#pragma

一般来说,我更喜欢
#pragma once
,因为当您复制头文件以便通过复制或扩展类进行增量重构时,您不能忘记更改include guard宏的名称


因此,除了某些编译器之外,我不知道您在使用
#pragma once
时遇到了什么困难。

我在使用
#pragma once
时遇到的一个问题是当包含位于多个位置的同一文件时。使用
#pragma once
被认为是不同的,而不是使用
#ifndef/#define
guard。

使用
#pragma once
就是放弃可移植性。您不再编写C或C++,但某些东西可以作为编译器扩展。 如果您的代码曾经针对不同的平台,那么这可能会让您头疼

正是因为这个原因,我从不使用它

鉴于文件的名称和位置是唯一的,我将其用作include保护。此外,因为我过去针对非常旧的预处理器,所以我习惯使用

#if !defined(foo)
#define foo 1
/*code*/
#endif

自1996年以来,它在我遇到的每个平台上都起作用。

“…您必须#取消页眉保护宏的定义以再次包含它…”我不明白您的意思?#pragma once方法也会出现同样的问题,但不允许页眉包含多次。”这不是缺点,而是唯一的目的。如果您想多次包含一个头,那么您根本不需要头保护
#pragma
一旦被添加以加速编译。您可以同时使用pragma和
#ifndef
“也许现在已经改变了。”是的,那是很久以前的事了。现在它说“如果在习惯用法的标准形式之前或之后没有非注释代码或预处理器指令,编译器将识别#include-guard习惯用法并以与#pragma-once指令相同的方式实现多重include优化”(@boperson:谢谢!我自己从来没有使用过MSVC++,只是在我的帖子中列出的那些。我已经更新了有关Microsoft编译器的部分。我不确定您使用的是什么平台,但完全支持C++11。@trudeaun:这是位于德国居里希的IBM Blue Gene/Q安装JUQUEEN。上次我尝试编译Chroma(一个晶格量子色动力学软件包)时,它与IBM编译器不兼容。
ixlc
(iSeries=AS400)不支持它吗?但是
xlc
/
xlc\u r
(AIX=Unix)有吗?是的。通过嵌套宏的范围循环也是超级可移植的。@Clear:这是我现实生活中的一个问题。不同的平台可以以不同的方式实现一次
#pragma
。大多数软件一开始做一些有趣的事情就放弃了可移植性。@Bathsheba:关于“给定文件的名称和位置是唯一的”,你是什么意思?您选择
foo
作为
PATH\u TO\u FILE
?或者您是否将预处理器与
\uuuuu FILE\uuuu
一起使用来获取路径?如果是后者,则如果某些构建环境足够混乱,符号链接可能会成为您的问题。
#pragma
是开发人员关于语言演变的首选:。IBM很特别,不要为它设计代码,记住它们是例外。最重要的是,不要携带