现代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除了我已经提到过的问题之外,还有哪些潜在的问题?我是否过于相信在实践中,无处不在?
(*)只有少数人使用的一些次要编译器,被排除在外.
到目前为止,我已经使用过一套不错的编译器:
唯一不支持#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,除了某些编译器之外,我不知道您有任何困难的问题。
在使用中#pragma once你放弃了便携性。您不再编写 C 或 C++,而是一些允许作为编译器扩展的东西。
如果您的代码针对不同的平台,那可能会让您头疼。
正是因为这个原因,我从不使用它。
鉴于文件的名称和位置是唯一的,我将其用作我的包含保护。此外,因为我过去曾针对非常旧的预处理器,所以我习惯使用
#if !defined(foo)
#define foo 1
/*code*/
#endif
Run Code Online (Sandbox Code Playgroud)
自 1996 年以来,它在我遇到的每个平台上都有效。