extern
extern可以用来进行链接指定;也可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。
与“C”连用(链接指定)
在CPP文件中经常可以看到类似下面这种形式的代码:
#ifdef __cplusplus
extern "C" {
#endif
/**** some declaration or so *****/
#ifdef __cplusplus
}
#endif /* end of __cplusplus */
那么,这种写法什么用呢?实际上,这是为了让CPP能够与C兼容而采用的一种语法形式。之所以采用这种方式,是因为两种语言之间的一些差异所导致的。
由于CPP支持多态性,也就是具有相同函数名的函数可以完成不同的功能,CPP通常是通过参数区分具体调用的是哪一个函数。在编译的时候,CPP编译器会将参数类型和函数名连接在一起,于是在程序编译成为目标文件以后,CPP编译器可以直接根据目标文件中的符号名将多个目标文件链接成一个目标文件或者可执行文件。但是在C语言中,由于完全没有多态性的概念,C编译器在编译时除了会在函数名前面添加一个下划线之外,什么也不会做(至少很多编译器都是这样干的)。由于这种的原因,当采用CPP与C混合编程的时候,就可能会出问题。
假设在某一个头文件中定义了这样一个函数:
int foo(int a, int b);
而这个函数的实现位于一个.c文件中,同时,在.cpp文件中调用了这个函数。那么,当CPP编译器编译这个函数的时候,就有可能会把这个函数名改成_fooii,这里的ii表示函数的第一参数和第二参数都是整型。而C编译器却有可能将这个函数名编译成_foo。也就是说,在CPP编译器得到的目标文件中,foo()函数是由_fooii符号来引用的,而在C编译器生成的目标文件中,foo()函数是由_foo指代的。但是在链接器工作的时候,它可不管上层采用的是什么语言,它只认目标文件中的符号。于是,连接器将会发现在.cpp中调用了foo()函数,但是在其它的目标文件中却找不到_fooii这个符号,于是提示连接过程出错。extern “C” {}这种语法形式就是用来解决这个问题的。
修饰声明全局变量或函数
举个例子,我们想要声明一个long int runtime_minute变量供多个模块使用:
//time.h
#ifndef TIME_H
#define TIME_H
//首先我们在time.h中进行以下声明:
extern long int runtime_minute;
#endif //TIME_H
在头文件中通过extern声明的变量并没有定义,所以要在time.cpp中给出定义:
//time.cpp
#include "time.h"
//在time.cpp中给出runtime_minute变量的具体定义:
long int runtime_minute = 0;
这时,如果想要在time2.cpp中使用这个定义在time.cpp中的runtime_minute变量,只需要包含time.h这个头文件即可:
//time2.cpp
#include "time.h"
#include <iostream>
//在time.cpp中给出runtime_minute变量的具体定义:
int main(){
runtime_minute++;
std::cout<<runtime_minute<<std::endl;
//输出为1
return 0;
}