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

Eon*_*nil 19 c c++

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

namespace AAA {
    extern "C" {
        #include "sqlite3.h"     // C API.
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

urz*_*eit 9

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

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

//main.h
main(void)
Run Code Online (Sandbox Code Playgroud)

在完成任何语法检查之前,会扩展预处理器宏.上面的例子将扩展为

int
main(void)
{
    return 1;
}
Run Code Online (Sandbox Code Playgroud)

这是合法代码.虽然你真的应该避免这样的例子,但有些情况下,包括在另一个元素中是非常有用的.在您的问题中,它取决于编译期间名称是如何被破坏的.如果声明了头文件中的所有定义extern "C",那么将在目标文件中对未命名的名称进行搜索,但是,如果包含该实现的目标文件在使用中没有使用与其定义相同的命名空间,则情况并非如此.代码并没有声明它extern "C".


Ton*_*roy 5

这是标准行为吗?

是的 - 标准支持该行为,因为C++编译器实际上没有代码概念为"C"与"C++",除非extern "C"用于禁止命名空间修改.

不禁止修改的结果是,如果您尝试链接到定义extern标头中提到的外部符号(变量,函数)的C库,则链接时可能会出现"未解析的符号"错误.

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

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

[an #include]导致由"delimiters"之间的指定序列标识的源文件的全部内容替换该指令.

所以,无论"C"标题发生什么,就好像周围的namespace/ extern语句和大括号存在于头文件的顶部和底部而不是......当编译的下一个阶段开始时它与源代码的确切位置无关来自(除了显示与源文件正确相关的错误消息之外).