【问题标题】:Can a C++ standard library header include a C standard header?C++ 标准库头文件可以包含 C 标准头文件吗?
【发布时间】:2016-06-02 10:26:43
【问题描述】:

我只能在标准草案 N4582 中找到

[res.on.headers/1] C++ 标头可能包含其他 C++ 标头。

似乎没有指定 C++ 标头是否可以包含 C 标准标头。

如果允许,使用 C 标准头文件中定义的全局名称是否不安全,即使该头文件不包含在内(因为程序可能通过某些 C++ 标准头文件隐式包含该头文件)?

【问题讨论】:

  • 我过去一直这样做(有效地将 C 和 C++ 代码混合在一起)并且它有效。是否按标准允许,我不能说。

标签: c++ c c++-standard-library


【解决方案1】:

就您跟进的问题而言(名称冲突),是的,当然可以。原因是 C++ 标准库包含 C 标准库内容的 <c:::> C++ 头文件,并且标准明确允许这些在全局命名空间中提供名称(除了强制在 ::std 中提供它们) .

此外,根据 C++ 标准的 Annex D [depr],C 标准库头文件(<:::.h> 版本)也是 C++ 标准库的一部分(尽管已弃用)。这意味着 [res.on.headers]/1 允许 C++ 标头包含它们。

【讨论】:

    【解决方案2】:

    C++ 标准的D.3 C standard library headers 部分使 26 个 C 标准头文件成为 C++ 的一部分。因此,这些是 C++ 的一部分。此外,许多其他 C 标头都遵循语言的共享子集(可能是 #ifdefing 一些事情),使它们成为有效的 C 和 C++ 标头。

    【讨论】:

      【解决方案3】:

      我的回答来晚了,但添加了其他人没有的东西,所以这里......

      简短回答:标准是否允许标准 C++ 标头包含标准 C 标头仍不清楚。

      其他答案已正确观察到 C++ 标准

      • 允许标准 C++ 标头
      • 包含标准 C++ 标头。

      目前还不清楚的是标准 C 头文件是否是标准 C++ 头文件。我可以同时提供证据。

      为什么 C 头文件确实是 C++ 头文件

      在带有 GNU 标准 C 库 2.24 的 GCC 6.24 上,以下测试无法编译。

      #include <iostream>
      
      namespace {
          const int printf {42};
      }
      
      int main()
      {
          std::cout << printf << "\n";
          return 0;
      }
      

      尽管测试缺少明确的#include &lt;cstdio&gt;,但编译器抱怨“对‘printf’的引用不明确”。

      GCC、GNU等主要编译器和标准库的开发者的判断力不容忽视。

      其他答案给出了进一步的理由,我不需要在这里重复。

      为什么 C 头文件不是 C++ 头文件

      C++17 标准(草案here),脚注 166,内容如下:

      [T]C 库工具的 C++ 头文件可以...在全局命名空间中定义名称。

      如果 C 头文件是 C++ 头文件,那么编写这样的脚注将是一种奇怪的方式,不是吗?相反,人们会期望脚注以“C 库设施的非&lt;*.h&gt; C++ 标头...”之类的词开头。

      最后的观察结果尚无定论,但在 [res.on.headers] 中,标准还写道:

      C 标准库头文件应仅包含其对应的 C++ 标准库头文件....

      同样,如果 C 标头在编写这些词的人的估计中是 C++ 标头,那么编写它们的方式似乎很奇怪。

      结论:模棱两可

      不幸的是,像其他回答者一样,我无法以标准的一种或另一种方式找到明确的答案。与其他回答者不同,我会得出结论,答案仍然模棱两可。标准中的相关部分包括 [contents]、[res.on.headers] 和 [depr.c.headers]。

      意见

      如果您想知道我认为哪种选择具有优势证据,那么我倾向于不同意其他答案。由于引用的原因,我倾向于说该标准不允许标准 C++ 标头包含标准 C 标头。无论如何,这种包含与普通的 C++ 用法相矛盾,因为这种包含使匿名全局命名空间更难使用。 [在我的测试中将printf 更改为foo,然后询问如果未来的标准C 库添加函数foo() 会发生什么。这样的实验说明了问题。]

      另一方面,与自己的工具链斗争是毫无意义的,不是吗?在 C++ 的未来版本明确之前,我的意思是避免在包含标准库头文件的源文件中使用匿名全局命名空间。

      我怀疑,由于该标准已弃用使用标准 C 标头的旧样式,因此标准委员会可能不会在此期间考虑如何用旧样式修补问题。也许 C++20 模块会提供一个简洁的解决方案。我们拭目以待。

      【讨论】:

        猜你喜欢
        • 2021-04-28
        • 1970-01-01
        • 2016-02-17
        • 2014-12-24
        • 1970-01-01
        • 1970-01-01
        • 2018-11-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多