我的回答来晚了,但添加了其他人没有的东西,所以这里......
简短回答:标准是否允许标准 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 <cstdio>,但编译器抱怨“对‘printf’的引用不明确”。
GCC、GNU等主要编译器和标准库的开发者的判断力不容忽视。
其他答案给出了进一步的理由,我不需要在这里重复。
为什么 C 头文件不是 C++ 头文件
C++17 标准(草案here),脚注 166,内容如下:
[T]C 库工具的 C++ 头文件可以...在全局命名空间中定义名称。
如果 C 头文件是 C++ 头文件,那么编写这样的脚注将是一种奇怪的方式,不是吗?相反,人们会期望脚注以“C 库设施的非<*.h> 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 模块会提供一个简洁的解决方案。我们拭目以待。