【问题标题】:Correct order for including both <cstdio> and <stdio.h>?包含 <cstdio> 和 <stdio.h> 的正确顺序?
【发布时间】:2010-11-04 15:36:02
【问题描述】:

我需要使用系统特定的功能,例如ftello()(根据 POSIX 标准在 stdio.h 中定义)。 我还需要使用标准 C++ 功能,例如std::sprintf()(在 cstdio 中定义,根据 ISO C++ 标准)。

AFAIK,仅包括 &lt;cstdio&gt; 并不能保证定义非标准 C++ 的东西,所以我想我必须包括两者。 我很久以前就读到过(例如)使用 gcc 可能存在包含文件顺序的问题。

那么,包含&lt;cstdio&gt;&lt;stdio.h&gt; 的正确顺序是什么? 我正在寻找一种尽可能跨平台的解决方案(至少对于 gcc、suncc、intel C++/linux 和 mingw)。

【问题讨论】:

    标签: c++ gcc include stdio


    【解决方案1】:

    对于系统头文件,包含顺序通常不应成为错误来源。

    对于其他头文件,请查看similar question here at SO

    【讨论】:

    • 感谢您的回答。我想我在这里发现了一个类似的问题:gcc.gnu.org/ml/libstdc++/2003-01/msg00210.html我实际上是在不久前偶然发现的,但我不记得细节了。标题绝对是系统通过的。虽然这是一个系统/编译器问题,但我要问的是,也许有人知道处理这类事情的尝试方法。
    【解决方案2】:

    我不知道任何真正的规则,但一般来说,我在高级库之前包含较低级别的系统库。

    所以在这种情况下 stdio.h 是一个 C 头文件,并且(在我的想象中)更接近机器,&lt;cstdio&gt; 是更高级别的 C++ 标准库,我认为它更抽象。

    我本人倾向于在cstdio 之前添加stdio.h,但我不知道支持该理由的确切理由。

    【讨论】:

      【解决方案3】:

      好的,经过更多的研究,我终于得出一个结论,首先包含 C++ 标头,然后再包含 C 标头是正确的做法。 例如,考虑以下 C++0x 标头(来自 gcc):

      /usr/include/c++/4.3/tr1_impl/cstdint:

      
      // ...
      #define __STDC_LIMIT_MACROS
      #define __STDC_CONSTANT_MACROS
      #include_next <stdint.h>
      // ...
      

      它的作用是定义了两个 C99 宏,然后才包含 C99 stdint.h 头文件。原因是在 C99 中,stdint.h 的某些功能是可选的,并且只有在定义了这些宏时才可用。但是,在 C++0x 中,所有 stdint.h 功能都是强制性的。 现在,如果我先包含 C99 stdint.h,然后再包含 cstdint,由于 stdint.h 中的标头保护,我不会获得强制性的 C++0x 功能。 有人可能会争辩说这是编译器供应商的错,但这是不正确的。 stdint.h 是一个系统捆绑的头文件(在本例中来自 glibc),它是一个 C99 头文件,对 C++0x(毕竟它可能是一个旧系统)或 gcc 一无所知。编译器无法真正修复所有系统头文件(在这种情况下,始终在 C++ 模式下启用这些功能),但它必须在这些系统上提供 C++0x 支持,因此供应商使用此解决方法。

      【讨论】:

        【解决方案4】:

        据我所知,ftello() 和 sprintf() 都包含在 stdio.h 中。

        包含顺序对于非标准标头可能很重要,您必须检查依赖结构以找出哪个依赖于另一个,并以正确的顺序包含它们。

        因此,包含文件的依赖关系应该包含​​在包含文件中,而不是依赖“用户”来确保它们被正确包含。

        【讨论】:

        • 是的,ftello() 和 sprintf() 来自 stdio.h,但我说的是 std::sprintf(),它可能与 sprintf() 相同也可能不同。事实上,它可能不是,因为 sprintf() 通常是编译器定义的宏,而 std::sprintf() 保证是一个函数(您可以获取它的地址)。所以,我需要使用来自 stdio.h 的 ftello() 和来自 cstdio 的 std::sprintf() 。两者都来自标准包含文件,但由于这两个文件有特殊关系,我不知道哪个是在各种编译器/操作系统组合上可靠工作的正确顺序。
        【解决方案5】:

        你无缘无故地担心。 &lt;cstdio&gt; 的内容“好像被包含”了 &lt;stdio.h&gt; (17.4.1.2 Headers/4) 的内容。不过,声明和定义(但不是宏)在命名空间 std 中。

        所以你可能需要写std::ftello()。为了提高便携性,请输入using std::ftello;,您也无需关心。

        【讨论】:

        • ftello() 不在 C++ 标准中,并且 std 命名空间中没有 ftello() (至少在 gcc 的 libstdc++ 中)。还是谢谢!
        • 这正是我的观点。 C++ 标准没有具体说明 stdio.h 中的内容。它只是说 cstdio 包含 stdio.h 中的任何内容,但在命名空间 std 中。如果 libstdc++ 将 ftello 放入 stdio.h 但未放入 cstdio,则违反 17.4.1.2。
        【解决方案6】:

        我把最具体的东西放在顶部,把最不具体的东西放在底部。例如,对于源文件,它看起来像这样:

        1. 预编译的头文件,如果有的话
        2. 此源文件的标题
        3. 项目包括
        4. 大多数特定库,例如此项目中的库或公司库
        5. 最少特定库,例如 boost 或 SDL 等“系统”库
        6. 标准 C++
        7. 标准C
        8. 操作系统头文件

        我的理由是更具体的标头通常会包含更通用的标头,并希望通过宏来修改它们。如果已包含这些,则包含警卫或默认宏值将破坏系统库的行为。

        另一个理由是,这种排序可以防止您“隐藏”来自其他头文件的依赖关系,也就是说,当从其他源文件中包含这些头文件时,这些头文件不会独立存在,因为它们之前总是包含系统库。

        【讨论】:

        • 这也是我的包含顺序。 :) 除了我出于某种原因将 5 移到 8 之后。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-12
        相关资源
        最近更新 更多