870920 Menu

SwingCoder之C++备忘录·23

extern详解

对象或变量名之前的extern关键字用于声明该变量或对象是外部编译单元中定义的。注意,不能说是外部文件中定义的,因为外部的头文件不是编译单元。

独立于函数与类之外的对象为全局性的,这样的对象只能定义并初始化一次,如果其他文件要使用这些对象,必须显式声明,并冠以extern前缀。因为C++中任何全局作用域内的对象只能定义一次(编译时分配内存,而初始化则是赋予其明确的内容,而非不确定的垃圾数据。定义而不初始化,则分配内存,而内存中却是垃圾数据),外部文件要使用这些全局性的对象,为防止重复定义而编译器报错,必须进行extern外部声明。

A文件中声明、定义并初始化了两个全局变量。二者都是指针,初始化为空指针:
ApplicationCommandManager* commandManager = nullptr;
ApplicationProperties* appProperties = nullptr;

B文件中如果要使用这两个全局性的对象,必须在文件开始处做外部声明,指明它们已在别处定义:
extern ApplicationCommandManager* commandManager;
extern ApplicationProperties* appProperties;

由上可知:全局对象默认可被项目中的任何文件所使用,只不过,需在使用它们的文件中进行extern声明。注意:定义时必须初始化的const常量对象,如果不加extern前缀,则只能在本文件范围内可用,外部文件即使用extern也不可用。如果外部文件需使用这类const常量对象,则定义和初始化该常量时就必须显式用extern关键字做声明,同时,要使用它的外部文件中同样也需要extern声明。比如:
// A文件中声明和初始化const常量。由于打算让其他编译单元使用,因此需使用extern前缀:
extern const int bufferSize = 1024;
// B文件中要使用该常量,必须做以下声明:
extern const int bufferSize;

对于全局函数,extern关键字可有可无。因为可以到处声明,而只在某个源文件中定义一次。

extern的另一个重要功能是作为“链接指示(禁止名称改编)”,即声明某些函数在编译和链接时使用外部特定的语言和名称,以及禁止编译器对这些函数进行名称改编。此时,必须在函数声明之前使用该关键字,而不能在函数定义中使用。可以声明一个函数用外部语言编译和链接,也可以一次性声明多个函数使用外部语言编译和链接。比如:

extern “C”
size_t strlen (const char*); // 声明该函数使用C语言编译和链接
extern “C” // 一次性声明多个函数使用非C++语言编译和链接
{
int strcmp (const char*, const char*);
char* strcat (char*, const char*);
}

使用第三方C库时,一个技巧是写一个h头文件,该头文件中使用extern关键字和#include预编译指令:
extern “C”
{
#include “libraryOfC.h”
}

上面只是C++编译链接时强制使用外部语言编译某个或某些函数,反过来,C++本身编译链接的函数也可以被外部语言所直接使用,此时,依然要用到extern关键字,所不同的,该关键字不是在函数声明时前缀使用,而是在函数定义时前缀使用。比如:
extern “C”
double calc (double parm)
{
// …函数定义语句
}
如此声明后,calc函数就可被C语言所编写的代码文件所调用了。