【问题标题】:Should I still use #include guards AND #pragma once?我还应该使用#include 警卫和#pragma 一次吗?
【发布时间】:2012-10-31 14:55:07
【问题描述】:

http://en.wikipedia.org/wiki/Pragma_once
当所有这些编译器都支持 #pragma once 时,我还应该使用包含防护吗?
很多关于堆栈溢出的响应都说要同时使用两者来实现兼容性,但我不确定这是否仍然正确。 今天有哪些编译器不支持#pragma once

我不确定这两种方法在被广泛采用之前是否只是一个建议,或者是否仍有充分的理由同时使用这两种方法。
仅使用#pragma once 会导致问题的任何示例?

【问题讨论】:

  • 请记住,列出的编译器的旧版本可能不支持它,所以如果您正在制作一个开源程序,其源代码将被分发,那么编译指示可能不起作用。
  • 这不仅仅是编译器的支持,还取决于环境的复杂程度。您是否相信编译器能够确定两个文件是否相同,包括所有网络挂载和符号链接?
  • 还可以考虑辅助工具,例如索引器和分析器。它们后面可能没有完整的预处理器或解析器,就像编译器一样。
  • 许多嵌入式系统使用旧的 RVCT(或 ADS)编译器。如果他们支持#pragma once,我会感到非常惊讶。
  • @Leo RVCT 从(至少)2.0 支持一次#pragma

标签: c++ compiler-construction pragma include-guards


【解决方案1】:

这取决于您的程序的可移植性。

只要您编写的程序应该与您知道肯定支持#prama once 的编译器一起工作,只需使用#pragma once 就足够了。但是这样做会将您的程序限制为支持实现定义功能的编译器集。

如果您需要您的程序在所有编译器上运行,那么您应该使用#pragma once 并同时包含防护。

如果编译器不支持#pragma once,它将简单地忽略它[Ref#1],在这种情况下,标头保护将为您服务,因此使用它们没有错当您不知道目标编译器支持的功能时。

因此,如果您希望您的程序在不同的编译器上 100% 可移植,理想的方法仍然是仅使用包含防护。正如@CharlesBailey 正确指出的那样,由于#pragma once 的行为是实现定义的,未知编译器上的行为可能会对您的程序产生不利影响。


[Ref#1]
标准 C++03:16.6 Pragma 指令

表单的预处理指令

# pragma pp-tokensopt new-line

使实现以实现定义的方式运行。 任何未被实现识别的编译指示都会被忽略。

【讨论】:

  • 如果您希望您的程序是 100.00% 可移植的,您需要使用包含保护,但您还需要避免使用 #pragma once,因为未知编译器上的实现定义行为可能会对你的程序。
  • @CharlesBailey:同意。答案需要修改。我会这样做的。感谢您指出。
  • #pragma once 如果同一文件在操作系统/文件系统级别使用两个不同的名称别名,则将失败。但是,无论文件系统引用如何,文件中的#include-guard 都将具有相同的名称,并且仍然有效。
【解决方案2】:

这是非标准的,所以如果你想安全使用包含警卫

【讨论】:

    【解决方案3】:

    正如您的表格所示,现在很少遇到不支持#pragma once 的主流编译器。为了保持代码库的清洁和维护成本低廉,需要不断地进行重构。每次重命名类或移动一些代码时都必须更新包含守卫,这给这项工作增加了很大的负担。

    所以我想说,除了一些小众角落案例或损坏的构建系统#pragma once 在实践中是可以安全依赖的。如果您关心生产力和代码质量,只使用 #pragma once 似乎是显而易见的选择。

    例外情况是,如果您正在编写一个库,该库需要支持所有的编译器,或者不幸地不得不使用这些不具备此功能的罕见编译器之一。

    【讨论】:

      猜你喜欢
      • 2012-08-04
      • 2021-06-03
      • 1970-01-01
      • 2010-11-11
      • 2010-12-20
      • 2016-09-17
      • 2014-04-09
      • 1970-01-01
      相关资源
      最近更新 更多