【问题标题】:When can you omit the file extension in an #include directive?什么时候可以在#include 指令中省略文件扩展名?
【发布时间】:2010-10-01 07:00:05
【问题描述】:

我在玩 gmock 并注意到它包含这一行:

#include <tuple>

我会期待tuple.h

什么时候可以排除扩展,它是否赋予指令不同的含义?

【问题讨论】:

    标签: c++ include c-preprocessor standards


    【解决方案1】:

    C++ 标准头文件没有“.h”后缀。我相信原因是该标准会破坏许多不同的标准前实现。因此,标准委员会没有要求供应商将其现有的“iostream.h”(例如)标头更改为符合标准(这将破坏其现有用户的代码),而是决定他们将删除后缀(我相信不会那么现有的实施已经完成)。

    这样,现有的非标准程序将继续使用供应商的非标准库工作。当用户想让他们的程序符合标准时,他们将采取的步骤之一是更改“#include”指令以删除“.h”后缀。

    所以

    #include <iostream>     // include the standard library version
    #include <iostream.h>   // include a vendor specific version (which by 
                            //      now might well be the same)
    

    正如其他答案所提到的,非标准库的编写者可以选择任一命名约定,但我认为他们希望继续使用“.h”或“.hpp”(正如 Boost 所做的那样)。原因:

    1. 如果 & 当库标准化时,标准版本不会自动覆盖以前的非标准版本(很可能会导致用户代码损坏)
    2. 似乎(或多或少)没有后缀的标头是标准库,而带有后缀的标头(旧的 C 标头除外)是非标准的。

    请注意,当委员会向 STL 添加哈希映射时,也发生了类似的问题 - 他们发现已经存在许多(不同的)hash_map 实现,因此没有提出一个破坏今天有很多东西,他们称标准实现为“unordered_map”。命名空间本应有助于防止这种类型的跳跃,但它似乎不够好(或使用得不够好),无法让他们在不破坏大量代码的情况下使用更自然的名称。

    请注意,对于“C”标头,C++ 允许您包含 &lt;cxxxxxx&gt;&lt;xxxxxx.h&gt; 变体。以“c”开头且没有“.h”后缀的声明将其声明放在std 命名空间(可能还有全局命名空间)中,带有“.h”后缀的声明将名称放置在全局命名空间中(一些编译器还将名称放在 std 命名空间中 - 我不清楚这是否符合标准,尽管我没有看到危害)。

    【讨论】:

    • 另一个(可能不是主要原因:))可能是指出标准头文件根本不需要是文件。所以他们本可以决定删除“.h”,因为它暗示了一个文件扩展名。
    • 自 ANSI C 1989 以来一直如此,它的脚注是:“头文件不一定是源文件......”顺便说一句 - 有没有人知道编译器做其他事情比标准头文件的普通源文件?
    • @MichaelBurr 预编译的头文件不符合这个要求吗?
    • 正确使用命名空间确实可以解决用户代码和标准库代码之间的任何潜在冲突,不幸的是,许多 STL 库的使用者在他们的源文件中都有某种形式的 using namespace std; 挥之不去,不幸的是 (因为在 C++ 中,向后兼容才是王道)委员会认为这需要使用不同的名称。
    【解决方案2】:

    伙计们,

    我认为交易是:#include 总是 pre将 /lib/include 挂到搜索路径(.h 是不受欢迎的),而 #include 只搜索 -我。

    请注意我可能是错的...这就是我认为它的工作方式(在 Solaris 上的 Forte cc 中)。

    【讨论】:

    • 你想错了——标准 C++ 没有指定搜索路径。
    • 承认你可能是错的,从而勉强避免了一个-1……你就是这样。 :-)
    【解决方案3】:

    除了已经发布的很好的答案之外,应该注意的是,C++ 标准不需要指令“#include &lt;iostream&gt;”来读取名为“iostream”甚至“iostream.h”的文件。它可以被命名为“fuzzball”。或者,可能不存在相应的文件,并且定义被构建到编译器中并由 include 指令激活。

    【讨论】:

      【解决方案4】:

      没有什么特别的事情发生。该文件被简单命名为tuple

      原因...标准库头文件没有文件扩展名是因为namespaces。

      命名空间是在游戏后期与 C++98 标准一起添加到 C++ 标准的,包括所有标准库实体所在的 std 命名空间。

      当标准库被移动到 std 命名空间时,这意味着所有现有的 C++ 代码都会中断,因为所有代码都希望该库位于全局命名空间中。解决方案是不理会旧的“dot-h”头文件,并在没有扩展名的文件中提供命名空间库。

      这样,#include&lt;iosteam.h&gt; 的旧代码可以期待一个全局的cout,而新代码可以#include&lt;iostream&gt; 并期待一个std::cout

      【讨论】:

      • 刚找到一个相反的说法,想指出来。彼得贝克尔指出"Namespaces have nothing to do with header names."
      • @DanielK。我认为这种说法是断章取义的。你读过彼得贝克尔的下一条评论吗?似乎在这个答案中复述了解释。
      • 我认为你是对的。 Peter Becker's next comment 声明“当标准库被放入 std 时,出现了向后兼容性的问题,显而易见的方法是从 iostream.h 更改为其他内容,我们几乎任意地决定使用不带扩展名的名称。 "
      【解决方案5】:

      我的理解是#include 元组将“指向” tuple.h。

      看看这个:iostream vs iostream.h

      【讨论】:

      • 编译器可能会决定这样做。从源代码中的字符串到操作系统的完整文件路径的转换取决于编译器。目录前缀很常见,但后缀扩展不是
      • 链接失效
      【解决方案6】:

      它包含一个简单命名为“元组”的文件——文件本身没有扩展名。

      C++ 包含文件的假定标准是在命名它们时不带 .h 扩展名;许多库编写者遵循此标准(STL 等),但有些不遵循。

      【讨论】:

      • 据我所知,Boost 文件的扩展名为 .hpp。
      【解决方案7】:

      如果文件名为tuple,则需要#include &lt;tuple&gt; 如果它被命名为tuple.h,那么你需要#include &lt;tuple.h&gt;

      就这么简单。您没有省略任何扩展名。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-31
        • 2017-04-25
        • 2010-12-28
        相关资源
        最近更新 更多