使用#pragma一次有什么危险?

Cle*_*rer 6 c c++ macros

现代C和C++编译器支持非标准的#pragma once预处理器指令,它与经典的头部保护器具有类似的用途:

#ifndef hopefully_unique_identifier_that_doesnt_hurt_the_code
#define hopefully_unique_identifier_that_doesnt_hurt_the_code
  // some code here
#endif
Run Code Online (Sandbox Code Playgroud)

一个问题,我知道,使用经典的方法是,一旦你包含一个标题,你必须#undef使用标题保护宏再次包含它(这样做,对我来说,是一个主要的代码气味,但那是除此之外).该方法也出现了同样的问题#pragma once,但没有允许多次包含标题的可能性.

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

在现实生活中,我很少遇到任何这些潜在问题,所以我并不认为它们是主要问题.

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

那么,#pragma once除了我已经提到过的问题之外,还有哪些潜在的问题?我是否过于相信在实践中,无处不在?

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

piw*_*iwi 9

我在使用#pragma once时遇到的一个问题是包含位于多个位置的同一文件.随着#pragma once它被认为是不同的,不是#ifndef/#define后卫.


Mar*_*ing 5

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

  • 海湾合作委员会
  • lang / LLVM
  • IBM XLC
  • 英特尔C ++编译器

唯一不支持#pragma once的编译器是IBM XLC编译器,该编译器甚至不支持C ++ 11,因此我不感兴趣。如果需要在Blue Gene / Q上使用IBM XLC编译器,则不能使用#pragma once。

很久以前,某些编译器不了解include Guard习惯用法,因此会反复打开头文件,只是发现预处理器将内容减少为零。对于这些编译器,使用#pragma once会给编译时带来好处。但是,这已经在主要的编译器中实现,因此如今这没有什么区别。

也许您的嵌入式系统有一些特殊的编译器。那可能无法使用#pragma once。

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

因此#pragma once,除了某些编译器之外,我不知道您有任何困难的问题。

  • *“也许现在已经改变了。” *是的,那是很久以前了。现在,它说:“如果在惯用语的标准格式之前或之后没有非注释代码或预处理器指令出现,则编译器会识别#include保护器惯用语并以与#pragma一旦指令相同的方式实现多重包含优化”(https: //msdn.microsoft.com/en-us/library/4141z1cx.aspx) (5认同)

Bat*_*eba 5

在使用中#pragma once你放弃了便携性。您不再编写 C 或 C++,而是一些允许作为编译器扩展的东西。

如果您的代码针对不同的平台,那可能会让您头疼。

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

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

#if !defined(foo)
#define foo 1
/*code*/
#endif
Run Code Online (Sandbox Code Playgroud)

自 1996 年以来,它在我遇到的每个平台上都有效。

  • 是的。通过嵌套宏进行范围循环也是超级便携的.. (4认同)
  • 大多数软件一开始做一些有趣的事情就放弃可移植性。 (3认同)