在底层代码和库的头文件中经常看到 __BEGIN_DECLS 和 __END_DECLS这两个宏,一直不太理解,今天特意查了一下,才知道它有这么大的用处。
首先看一下他们的宏定义:
sys/cdefs.h
#if defined(__cplusplus)
#define __BEGIN_DECLS extern "C" {
#define __END_DECLS }
#else
#define __BEGIN_DECLS
#define __END_DECLS
我们编写代码,经常需要c和c++混合使用,为了使 C 代码和 C++ 代码保持互相兼容的过程调用接口,需要在 C++ 代码里加上 extern “C” 作为符号声明的一部分,为了简化,从而定义了上面的两个宏方便我们使用。
1. extern "C"
extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。
加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般只包括函数名。
可以把其看成extern 和 “C”:
1.1 extern
代表是声明为外部,即定义的地方可能不在当前作用域。
例如,在函数内部声明:
int func()
{
extern int a;
...
...
}
变量 a 定义在别的地方,可能是func 下面,也可能在func所在文件外面。
extern 修饰的函数也是一样,不过函数定义的地方就是有函数体的地方。一般extern修饰的函数在头文件中,函数体放在c文件中,这样就实现了声明和定义分离。
1.2 “C”
这里表示声明的部分是C部分。C++是C的超集,当时C和C++编译器不同,因为C++中存在函数的重载,所以在编译的时候会变成函数名加上参数类型,而C编译的时候只是函数名。
例如:
void func(int, int);
在C++编译后,目标文件中函数符号名变成__func_int_int,而C编译后仅为__func。
所以,如果C++中使用C中的函数,不做声明的时候是提示找不到该函数,因此,C++中想要使用C接口(在C的编译工具链编译出来的目标文件中),需要加上声明,如下:
#ifdef __cplusplus
extern "C" {
#endif
void fun(int, int);
#ifdef __cplusplus
}
#endif