本人在过去学习c++的过程中,一直没有特别在意头文件的包含法则,以及声明和定义的区别,感觉基本上也是相安无事。因此也未曾仔细学习extern的用法,今天又学习c++primer到2.4节,下定决心要把这个搞明白。
经过网上查阅资料,关于“什么时候使用extern”,有一个入门的原则:链接时不出错……
首先我假设你已经了解了定义和声明的区别以及头文件在预处理时的展开。那么可以接下来看我浅析以下……
首先对于任何变量和函数都只能定义一次,不然就会出现重定义的报错。在我使用vs2010的过程中,发现有些重定义是只有warning的("xx" 已在 ff.obj 中定义;已忽略第二个定义),这个本来应该是error的问题都已经淡化成warning了……言归正传,正因为定义操作必须只能出现在一次,而某个头文件可能被多个源文件包含(即使使用预编译宏处理,每个源文件都只包含一次头文件),因此在程序运行的全局范围内就出现了重定义。
请看下面例子:
/*file1.h*/
#ifndef FILE1_H
#define FILE1_H
int x=0; //定义
#endif
/*file2.cpp*/
#include file1.h
……
/*file3.cpp*/
#include file2.h
……
这个例子中,因为x是全局变量(”非const变量默认为extern“——《c++primer》),因此x重定义了,编译器将在链接时报错。为了避免重定义,有两种解决方法:一是使用“extern”,将头文件中的定义变成声明。
/*file1.h*/
#ifndef FILE1_H
#define FILE1_H
extern int x; //声明
#endif
/*file1.cpp*/
#include file1.h
int x=0; //定义
/*file2.cpp*/
#include file1.h
……
/*file3.cpp*/
#include file2.h
……
二是使用”const"修饰符x变为文件局部变量(已经变为常量了,因此有些受限)-作用域在该文件内
/*file1.h*/
#ifndef FILE1_H
#define FILE1_H
const int x=0; //定义
#endif
/*file2.cpp*/
#include file1.h
……
/*file3.cpp*/
#include file2.h
……
补充一句,const修饰的变量也可以通过“extern"修饰,将作用域变为全局。
/********************************分割线*********************************************/
以上是有关变量的使用extern的一个情形。下面浅谈一下有关函数的extern
由于函数的声明不需要使用”extern"就能办到,因此较少见到extern 修饰函数。往往在c和c++混合调用中比较常见,使用方式如下(未测试……):
/*file1.h */
#ifndef FILE1_H
#define FILE1_H
extern void fun1(); //"extern"可省略
#endif
/*file1.c*/
#include "file2.h"
extern void fun2(); //声明以c++格式定义的函数fun2
void fun1(){} //定义fun1
/*some operation of fun2*/
/*file2.h*/
extern "c" void fun2(); //extern "c"不能省略
/*file2.cpp*/
#include "file1.h"
extern "c" void fun1(); //声明以c格式定义的函数fun1
void fun2(){}
/*some operation of fun1*/