【问题标题】:What is the reason for #pragma once inside header guards?#pragma once 进入头守卫的原因是什么?
【发布时间】:2010-08-13 09:56:14
【问题描述】:

刚刚在<boost/asio.hpp>看到这个

#ifndef BOOST_ASIO_HPP
#define BOOST_ASIO_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

/// ....

#endif // BOOST_ASIO_HPP

忽略_MSC_VER 预处理器检查,在这种情况下使用#pragma once 有什么好处?预处理器标头保护不是在所有情况下和所有平台上都确保标头内容只有included 一次吗?

【问题讨论】:

    标签: c++ boost c-preprocessor header-files pragma


    【解决方案1】:

    #pragma once 指定编译器在编译源代码文件时将包含(打开)文件一次。这可以减少构建时间,因为编译器不会在模块的第一个 #include 之后打开和读取文件。

    如果您不#pragma once,文件将在每次需要时打开,如果已定义,编译器将停止在#ifndef BOOST_ASIO_HPP 上解析它。

    【讨论】:

    • 如果我们有#pragma,您是说打开标题并只读取一次?标头守卫意味着文件总是打开但守卫中的内容被跳过,对吧?我的理解正确吗?如果我能证明这一点,我会看到它发生:)
    • 如果是#pragma once,它并不总是打开。该指令使编译器记住不要再次打开它(不止一次)。这就是为什么这个指令优于#ifndef,它可以被省略。然而,许多人仍然使用 #ifndef 来支持无法识别 #pragma 一次的旧编译器。
    【解决方案2】:

    【讨论】:

    • 好的。我理解头卫的目的。问题是为什么我们有header guard 和pragma one
    • @MeThinks - 可能不是所有的实现都支持这个 pragma,所以你仍然想防止你的 header 被多次处理。编译指示在这里是一个额外的好处。
    • 我在答案中给出的 SO 链接中回答了很多问题。
    【解决方案3】:

    是的标头保护确保标头内容仅包含一次。但是在这里您使用#pragma 来检查另一个定义而不是包含文件。

    以下链接是关于 SO 中标头保护的现有问题。

    Purpose of Header guards

    【讨论】:

    • 标题守卫无论如何都会这样做,对吗?为什么还需要#pragma once?
    • 标头保护告诉预处理器它必须静默文件中从#ifndef#endif的所有行,但假设预处理器读取整个文件,并且不输出任何结果为块。 #pragma once 告诉预处理器以后任何包含相同文件的#include 都将被忽略。不同之处在于,在后一种情况下,预处理器甚至不会打开文件并进行检查。话虽这么说,#pragma once 不是标准的,编译器已经逐渐理解包含保护模式,应该没有太大区别。
    • @MeThinks - 可能不是所有的实现都支持这个 pragma,所以你仍然想防止你的 header 被多次处理。编译指示在这里是一个额外的好处。 (评论来自另一个答案)
    【解决方案4】:

    #pragma once 具有相同的目的,但包含防护旨在需要更深入的分析以确保文件只包含一次 - 例如

    // somerandomfileinmyproject.cpp
    #undef BOOST_ASIO_HPP 
    #include <bost/asio.cpp>
    

    除非编译器确实正确处理了这种情况,否则它仍然需要打开文件并将其传递给预处理器,即使它之前已经包含在内。

    【讨论】:

      【解决方案5】:

      您可以使用以下方法以标准方式重现 #pragma once 的效果:

      #if !defined GUARD_SYMBOL
      #include "GUARDED_FILE"
      #endif
      

      虽然它更冗长。正如其他人所说,它有助于编译时间,因为不搜索/打开文件而不是打开文件并忽略其中的所有内容 - 文件仍然必须由预处理器解析。

      【讨论】:

      • 正如 David 上面提到的,大多数现代编译器(尤其是 gcc)对标头保护模式的理解已经足够好,可以跳过重新解析部分,并且表现得好像有一次编译指示或好像代码是编写的你在这里展示的方式。这一点,以及 pragma once 无法正确处理某些极端情况的事实也是 pragma once 被积极拒绝引入新 C++0x 标准的原因。另见SO disscussion
      猜你喜欢
      • 2010-10-21
      • 1970-01-01
      • 2016-09-17
      • 2011-06-01
      • 2010-11-11
      • 2016-04-26
      • 2017-11-27
      • 2011-08-12
      相关资源
      最近更新 更多