在 C++ 命名空间中包含 C 标头 - 这是标准行为吗?

Including C headers in a C++ namespace - is it a standard behavior?

本文关键字:标准 命名空间 C++ 包含 标头      更新时间:2023-10-16

我一直认为C头文件必须包含在C++程序的顶层。 无论如何,我意外地发现C++允许在子命名空间中包含 C 标头。

namespace AAA {
extern "C" {
#include "sqlite3.h"     // C API.
}
}

然后,所有 C 类型和函数都将放置在命名空间中。更有趣的是,所有链接的C函数也都在工作!我还发现这可能会导致一些预处理器问题,但除此之外,它似乎工作得很好。

这是标准行为吗?(我正在使用Clang 3.x)如果是,此功能的名称是什么,在哪里可以找到标准中提到的此功能?

你甚至可能会做一些奇怪的事情,比如

//test.c
int
#include "main.h"
{
return 1;
}
//main.h
main(void)

在执行任何语法检查之前,将展开预处理器宏。上面的例子将扩展到

int
main(void)
{
return 1;
}

这是法典。虽然您确实应该避免使用此类示例,但在某些情况下,包含在另一个元素中非常有用。在您的问题中,这取决于在编译过程中名称是如何被篡改的。如果头文件中的所有定义都使用extern "C"声明,则名称将在目标文件中未被搜索,但是,如果包含实现的对象文件不使用与它在消费代码中的定义相同的命名空间并且未将其声明为extern "C",则情况并非如此。

这是标准行为吗?

是的 - 该行为受标准支持,因为C++编译器实际上没有代码是"C"与"C++"的概念,除非extern "C"用于抑制命名空间重整。

不禁止重整的结果是,如果您尝试与定义标题中提到的行外符号(extern变量、函数)的 C 库链接,则可能会在链接时出现"未解决的符号"错误。

如果是[标准功能],此功能的名称是什么,在哪里可以找到标准中提到的此功能?

这只是#include工作方式的结果,在 16.2 源文件包含 [cpp.include] 中定义,至关重要的是:

[#include] 导致该指令被由 " 分隔符之间的指定序列标识的源文件的全部内容替换。

因此,无论"C"标头发生什么,都与头文件的顶部和底部存在周围的namespace/extern语句和大括号完全相同......当编译的下一阶段开始时,源代码的确切来源无关紧要(除了显示与源文件正确相关的错误消息)。