C++标准库头文件能否包含C标准库头文件?

15

我只能在标准草案N4582中找到以下内容:

[res.on.headers/1] C++头文件可以包含其他C++头文件。

它似乎并没有指定一个C++头文件是否可以包含C标准头文件。

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


我过去经常这样做(有效地混合使用C和C++代码),而且它可以工作。至于是否符合标准,我无法说。 - user1023602
3个回答

5
针对您跟进的问题(名称冲突),是的,确实可以。原因是C++标准库包含C标准库内容的 C ++头文件,标准明确允许它们在全局命名空间中提供名称(除了必须在<::std>中提供它们之外)。
此外,根据C ++标准的附录D [depr],C标准库头文件(<:::.h>版本)也是C++标准库的一部分(虽然已弃用)。这意味着[res.on.headers] / 1允许C++头文件将它们包含在内。

4

C++标准的第D.3 C standard library headers节将26个C标准头文件包含在C++中。因此,它们是C++的一部分。此外,许多其他C头文件遵循语言的共享子集(可能通过#ifdef排除一些内容),使它们成为有效的C和C++头文件。


0

我的回答来晚了,但是我会补充一些其他人没有提到的内容。

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

其他回答正确地观察到:

  • 允许标准的C++头文件
  • 包含标准的C++头文件。

不清楚的是,标准的C头文件是否是标准的C++头文件。 我可以提供两种证据。

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

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

#include <iostream>

namespace {
    const int printf {42};
}

int main()
{
    std::cout << printf << "\n";
    return 0;
}

编译器抱怨,“对‘printf’的引用不明确”,尽管测试缺少显式的#include <cstdio>
像GCC和GNU这样的主要编译器和标准库的开发人员的判断是很难被忽视的。
其他答案已经给出了进一步的原因,我不必在此重复。
为什么C头文件不是C++头文件
C++17标准(草案here),脚注166,写道:
“C库设施的C++头文件可能会在全局命名空间中定义名称。”
如果C头文件是C++头文件,那么这将是一个奇怪的方式来编写这样的脚注,不是吗?相反,人们预计脚注应该以类似于“非<*.h> C++头文件的C库设施...”的话开始。
最后的观察结果并不确定,但在[res.on.headers]中,标准还阅读到:
“C标准库头文件只包括它们相应的C++标准库头文件...”

如果C头文件在撰写这些文字的人看来是C++头文件,那么这似乎是一种奇怪的写法。

结论:模棱两可

不幸的是,像其他回答者一样,我无法在标准中找到明确的答案。与其他回答者不同的是,我认为答案仍然是模棱两可的。标准中相关的部分包括[contents]、[res.on.headers]和[depr.c.headers]。

观点

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

另一方面,与其抵抗工具链,不如避免在包含标准库头文件的源文件中使用匿名全局命名空间,这样做似乎相当无意义,不是吗?我猜想,既然标准已经弃用了使用标准 C 标头的旧风格,标准委员会可能不会太费心思来修补旧风格的问题。也许 C++20 模块将提供一个简洁的解决方案。我们拭目以待。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接