extern关键字的使用
标签(空格分隔):c/c++
C++为了与C兼容,C++可以使用关键字extern “C”来声明或者定义一个C符号:
extern "C"{ int func(int); int var; }
C++会将extern “C”的大括号内的代码当做C语言代码(.c文件)处理,亦即在大括号中C++的名称修饰机制将不起作用,不同的编译器有不同的名称修饰方法:
1.如果是VC++平台,上述代码中的fun和var会被修饰(名称修饰)为_func和_var;
2.但是如果是linux下的gcc编译器,前面的_也会被去掉,extern “C”里面的符号就是修饰后符号(为func和var)。
【补充】gcc编译.c文件,因为是按照c方式编译,所以函数名不变;gcc编译.cpp文件,g++编译.c文件,g++编译.cpp文件,因为是按照c++方式编译,所以函数名才会加上了附加信息。(当前编译器编译出来的目标文件和库文件(目标文件)应该是同样的编译器编译出来的)
ps:单独声明某个函数或者是变量是C的符号,可以直接extern "C" int func(int);
extern “C”带来的问题
我们经常遇到这样的情况:有些头文件声明了一些C语言的函数和变量,但是这个头文件可能被C语言或者是C++语言包含。例如:
对于函数 void *memset (void *, int, size_t) 而言,如果不使用extern “C”,考虑一以下两种情况:
1.在C语言程序包含string.h的时候,如果用到了memset这个函数,编译器会进行正确的函数名称修饰_memset(C语言的名称修饰,前面加_),也可以正确的连接到C语言库中的memset符号。
2.在C++程序中包含了memset函数,编译器编译器会认为这是一个C++函数,函数名就会被修饰为_Z6memsetPvii(C++的名称修饰可自行了解),这样的话,链接器就没办法在C语言的库中找到对应的符号地址。此时就必须使用extern “C”。C与C++的兼容问题的实现
方法是使用C++的宏__cplusplus#ifdef __cplusplus extern "C" { #endif // 代码 #ifdef __cplusplus } #endif
含义是,如果是C++代码,那么memset会在extern “C”中被声明,如果是C代码就直接声明。
关于extern在函数指针使用情况下的使用举例
一个例子:
(1)工程下面 global.h 中... typedef void(*xivc_picture_data_t)(img_params *img); ... extern xivc_picture_data_t decode_image; // important ...
(2)工程下面 ldecode.c 中
#include "global.h" ... xivc_picture_data_t decode_image; // important ... decode_image = picture_decode_mt; ...
(3)工程下面 image.c 中方可使用decode_image
#include "global.h" ... decode_image(img); ...
等价如下
【ldecode.c】typedef void(*xivc_picture_data_t)(img_params *img); ... xivc_picture_data_t decode_image; // important ... decode_image = picture_decode_mt; ...
【image.c】
extern xivc_picture_data_t decode_image; // important ... decode_image(img); ...
记录
上述情况下的extern的使用是基本的使用方式
在头文件中:extern int g_Int;
它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块或其他模块中使用,记住它是一个声明而不是定义!
比如,在源文件A里定义的函数,在其它源文件里是看不见的(即不能访问)。为了在源文件B里能调用这个函数,应该在B的头部加上一个外部声明:
extern 函数原型;
这样,在源文件B里也可以调用那个函数了。注意这里的用词区别:在A里是定义,在B里是声明。一个函数只能(也必须)在一个源文件里被定义,但是可以在其它多个源文件里被声明。定义引起存储分配,是真正产生那个实体。而声明并不引起存储分配。打一个粗俗的比方:在源文件B里声明后,好比在B里开了一扇窗,让它可以看到A里的那个函数。基本规则
extern用在变量声明中常常有这样一个作用,你在*.c文件中声明了一个全局的变量,这个全局的变量如果要被引用,就放在*.h中并用extern来声明。注意
另外一种方法是在公共的*.h文件中使用全局变量,两个*.c文件同时include该.c文件,就可以避免使用extern,也可以做到函数的更新同步。上述例子中,直接在global.h文件中使用xivc_picture_data_t decode_image;
即可。但是,上述方法可能会引起重复定义的问题,最好的方法还是使用extern,养成好的习惯。- 补充
在一个.c文件的最前面使用extern int f(); 和int f();是等效的,都说明了f函数可能在其他函数中定义,而在当前函数中只是声明一下有待使用。但是最好还是使用extern关键字,避免误解。