我一直认为C头文件必须包含在C ++程序的顶层。 无论如何,我偶然发现C ++允许在子命名空间中包含C头。
namespace AAA {
extern "C" {
#include "sqlite3.h" // C API.
}
}
然后,所有C类型和函数都将放在命名空间中。更有趣的是,所有链接的C函数也正常工作!我还发现这可能会导致一些预处理器问题,但除此之外,它似乎工作得很好。
这是标准行为吗? (我使用的是Clang 3.x)如果是,这个功能的名称是什么?我在哪里可以找到标准中提到的这个功能?
答案 0 :(得分:9)
你甚至可以做一些奇怪的事情,比如
//test.c
int
#include "main.h"
{
return 1;
}
//main.h
main(void)
在完成任何语法检查之前,会扩展预处理器宏。上面的例子将扩展为
int
main(void)
{
return 1;
}
这是合法代码。虽然你真的应该避免这样的例子,但有些情况下,包括在另一个元素中是非常有用的。在您的问题中,它取决于编译期间名称是如何被破坏的。如果头文件中的所有定义都是使用extern "C"
声明的,那么将在目标文件中对未命名的名称进行搜索,但是,如果包含该实现的目标文件不使用相同的命名空间,则情况并非如此。它是消费代码中的定义,并未声明它extern "C"
。
答案 1 :(得分:5)
这是标准行为吗?
是的 - 标准支持这种行为,因为C ++编译器实际上并没有“C”与“C ++”的代码概念,除非使用extern "C"
来禁止命名空间修改。
如果您尝试链接到定义外部符号(extern
变量,函数的C库,则可能会在链接时最终导致“未解决的符号”错误)在标题中提到。
如果是[标准功能],此功能的名称是什么?我在哪里可以找到标准中提到的此功能?
这只是#include
工作方式的结果,它在16.2源文件包含[cpp.include]中定义,至关重要:
[an
#include
]导致由“delimiters”之间指定序列标识的源文件的全部内容替换该指令。
因此,无论“C”标题发生什么,就像在头文件的顶部和底部存在周围的namespace
/ extern
语句和大括号一样......编译的下一个阶段开始与源代码的确切位置无关(除了显示与源文件正确相关的错误消息之外)。