预处理器内部的命名空间解析



我有一个在C可执行文件和一个大型C++代码库之间共享的.h头。

#ifdef __cplusplus
namespace my {
#endif
typedef int my_t;
#define MY_OH_MY sizeof(my_t)
typedef my_t alias_t;
// plenty of other typedefs which push me to keep only
// these two bracing #ifdef __cplusplus ...
#ifdef __cplusplus
} // namespace
#endif

C源代码在排除条件下运行良好。

#include "my.h"
int main(int argc, char ** argv)
{
my_t m = 1;
alias_t a = 2;
m += MY_OH_MY;
return 0;
}

然而,CXX源在Gnu编译器下失败:

#include "my.h"
int main(int argc, char ** argv)
{
my::my_t m = 1;
my::alias_t a = 2;
m += MY_OH_MY;
return 0;
}

my.h:7:25:错误:未在此范围中声明"my_t";你的意思是"my::my_t"吗?7 |#define MY_OH_MY sizeof(MY_t(

主要是因为(?(在预处理器时命名空间仍然不是一件事吗?我原以为在任何情况下它都会属于namespace { }封闭组。

我当然可以把它改成下面的,但我仍然不明白为什么它不起作用。

#ifdef __cplusplus
#define MY_OH_MY sizeof(my::my_t)
#else
#define MY_OH_MY sizeof(my_t)
#endif

您不能在必须从C访问的C标识符中使用名称空间(因为它不是C语言的一个功能(。事实上,您必须特别声明这些名称空间,以便编译器不会篡改名称。您只能在C++中使用它们,但要小心与C共享代码,您必须通知C++编译器哪些例程和哪些标识符将从C中可见(编译器以不同的方式篡改名称,以包括有关运算符定义、参数列表和重载以及名称空间的信息(,从而使标识符对程序员来说完全是神秘的。

要查看示例,只需编写以下函数:

char *function1(char *parameter1, int parameter2)
{
return 0;
}

并将其编译为C语言(以.c后缀命名文件(和C++语言(使用.cc作为文件后缀(。然后使用nm(1)查看编译器用于命名函数的名称。###作为C代码(在文件func.c中(:

$ make func.o
cc  -O2 -pipe -c func.c -o func.o
$ nm func.o
0000000000000000 T function1
$ _

###现在作为C++代码(在文件func.cc中(:

$ make func.o
c++ -O2 -pipe -c func.cc -o func.o
$ nm func.o
0000000000000000 T _Z9function1Pci
$ _

_Z表示编译器的某些内容,9表示9个字符长的标识符(function1(,P表示指针,c表示chari表示整数参数。

如果您在C++中编译了它,但在extern "C" { }块中声明了它,那么名称将与第一个示例中的名称相同,但您不应该定义另一个名称为function1和不同参数列表的函数,因为已经有一个名为function1:的C函数

#ifdef __cplusplus
extern "C" {
#endif
/* C++ functions that will be accessible from C code, or C function
* declarations that will be accessed from C++ code, depending on which
* source you include this code */
#ifdef __cplusplus
} /* extern "C" */
#endif

最新更新