extern “C”的意义
在嵌入式领域,很多C文件内会出现如下的代码:
#ifdef __cplusplus
extern "C"
{
#endif
/*add function declaration here*/
#ifdef __cplusplus
}
#endif
Q:为什么会出现这样的代码段呢?
A:个人理解,为了在嵌入式编译环境下(如Keil或者IAR)可以同时支持Cpp文件和C文件!Cpp文件对C文件内的函数引用!C语言不支持extern “C”语法,如果我们想写一个头文件,同时支持被C和C++引用,就可以使用这样的办法,使用C++的宏”__cplusplus”来判断是不是C++编译器,用于指示编译器此段代码应按照C语言进行编译!不懂的话,还请继续往下看!
Q::为什么这段代码就可以起到同时支持Cpp和C文件呢?
A:由于C++支持函数重载,因此编译器在编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名,举例 void func(int x,int y) 会被编译为__func_int_int符号,void func(float x,float y)会被编译为__func_float_float函数;而C语言不支持函数重载!在编译C语言代码的函数时不会带上参数列表中的信息,如函数void func(int x,int y)会被编译为__func符号;所以说如果有遇到一种情况是C++文件需要调用C文件内的函数是,如果不加以extern “C”
声明修饰,则会出现C++文件和C文件在链接时,找不到对应的函数体声明,则会报错!具体可参考下面例子:
被extern "C"修饰的变量和函数是按照C语言方式进行编译和链接的:这点很重要!!!!
举个例子:
A员工和B员工,A使用C语言写程序,B使用CPP写程序
A:
A.h
#ifdef __A_H
#define __A_H
void func(int x);
#endif
A.c
#include "A.h"
void func(int x)
{
add user code here!
}
A是C语言编写的,所以编译后func(int x)被编译为_func函数
B:
B.h
#ifdef __B_H
#define __B_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "A.h"
#ifdef __cplusplus
}
#endif
#endif
B.cpp
#include "A.h"
#include "B.h"
int main(void)
{
func(2);
}
B在添加了 extern “C” 这段代码后,被编译为_func符号,如果没有添加这段代码,因为C++函数重载的特性,就会编译为__func_int符号会附带上参数列表,所以在B.CPP调用时,B文件就会在A.obj文件中寻找__func_int符号,所以这必然是找不到的,这也就是extern “C”声明的意义!看到这里应该就一清二楚了!
Q:那extern “C”后面可以如何添加声明呢?
A:
1. 单一语句;
2. 可以是复合语句, 相当于复合语句中的声明都加了extern “C”;
extern "C"
{
double sqrt(double);
int min(int, int);
}
3. 可以包含头文件,相当于头文件中的声明都加了extern “C”;
extern "C"
{
#include <cmath.h>
}
4. 不可以将extern “C” 添加在函数内部
5. 如果函数有多个声明,可以都加extern “C”, 也可以只出现在第一次声明中,后面的声明会接受第一个链接指示符的规则。
6. 除extern “C”, 还有extern “FORTRAN” 等。
参考文章:
extern C的作用详解