chenbaohai的专栏

extern

 谨记:声明可以多次,定义只能一次。

这个关键字真的比较可恶,在声明(函数)的时候,这个extern居然可以被省略,所以会让你搞不清楚到底是声明还是定义,下面分变量和函数两类来说:

(1)变量

尤其是对于变量来说。

extern int a;//声明一个全局变量a

int a; //定义一个全局变量a,外部变量如果没有初始化其值为0

extern int a =0 ;//定义一个全局变量a 并给初值。

int a =0;//定义一个全局变量a,并给初值,

声明之后你不能直接使用这个变量,需要定义之后才能使用。

第四个 等于第 三个,都是定义一个可以被外部使用的全局变量,并给初值。

糊涂了吧,他们看上去可真像。但是定义只能出现在一处。也就是说,不管是int a;还是extern int a=0;还是int a=0;都只能出现一次,而那个extern int a可以出现很多次。

当你要引用一个全局变量的时候,你就要声明extern int a;这时候extern不能省略,因为省略了,就变成int a;这是一个定义,不是声明。

(2)函数

对于函数也是定义和声明,定义的时候用extern,说明这个函数是可以被外部引用的,声明的时候用extern说明这是一个声明。 但由于函数的定义和声明是有区别的,定义函数要有函数体,声明函数没有函数体,所以函数定义和声明时都可以将extern省略掉,反正其他文件也是知道这个函数是在其他地方定义的,所以不加extern也行。两者如此不同,所以省略了extern也不会有问题。

比如:

int fun(void)

{

return0;

}

很好,我们定义了一个全局函数

int fun(void);

我们对它做了个声明,然后后面就可以用了

加不加extern都一样

我们也可以把对fun的声明 放在一个头文件里,最后变成这样

int fun(void);//函数声明,所以省略了extern,完整些是extern int fun(void);

intfun(void)

{

return0;

}//一个完整的全局函数定义,因为有函数体,extern同样被省略了。

然后,一个客户,一个要使用你的fun的客户,把这个头文件包含进去,ok,一个全局的声明。没有问题。

但是,对应的,如果是这个客户要使用全局变量,那么要extern 某某变量;不然就成了定义了。

总结下:

  对变量而言,变量的声明有两种情况: 一种是需要建立存储空间的不用加extern;2、另一种是不需要建立存储空间需要加extern 。如果你想在本源文件中使用另一个源文件的变量,就需要在使用前用extern声明该变量,或者在头文件中用extern声明该变量;

  对函数而言,如果你想在本源文件中使用另一个源文件的函数,就需要在使用前用声明该变量,声明函数加不加extern都没关系,所以在头文件中函数可以不用加extern。

extern "C"的用法

链接指示符extern C

如果程序员希望调用其他程序设计语言尤其是C 写的函数,那么调用函数时必须告诉编译器使用不同的要求,例如当这样的函数被调用时函数名或参数排列的顺序可能

不同,无论是C++函数调用它还是用其他语言写的函数调用它,程序员用链接指示符linkage directive 告诉编译器该函数是用其他的程序设计语言编写的,链接指示符有两种形式既可以是单一语句single statement 形式也可以是复合语句compound statement形式。

// 单一语句形式的链接指示符

extern "C" void exit(int);

// 复合语句形式的链接指示符

extern "C" {

int printf( const char* … );

int scanf( const char* … );

}

// 复合语句形式的链接指示符

extern "C" {

#include <cmath>

}

链接指示符的第一种形式由关键字extern 后跟一个字符串常量以及一个普通的函数,声明构成虽然函数是用另外一种语言编写的但调用它仍然需要类型检查例如编译器会检查传递给函数exit()的实参的类型是否是int 或者能够隐式地转换成int 型,多个函数声明可以用花括号包含在链接指示符复合语句中,,这是链接指示符的第二种形式花扩号被用作分割符表示链接指示符应用在哪些声明上在其他意义上该花括号被忽略,所以在花括号中声明的函数名对外是可见的就好像函数是在复合语句外声明的一样,例如在前面的例子中复合语句extern "C"表示函数printf()和scanf()是在C 语言中写的,函数因此这个声明的意义就如同printf()和scanf()是在extern"C"复合语句外面声明的一样,当复合语句链接指示符的括号中含有#include 时在头文件中的函数声明都被假定是用链接指示符的程序设计语言所写的在前面的例子中在头文件<cmath>中声明的函数都是C函数链接指示符不能出现在函数体中下列代码段将会导致编译错误。

int main()

{

// 错误: 链接指示符不能出现在函数内

extern "C" double sqrt( double );

double getValue(); //ok

double result = sqrt ( getValue() );

//…

return 0;

}

如果把链接指示符移到函数体外程序编译将无错误

extern "C" double sqrt( double );

int main()

{

double getValue(); //ok

double result = sqrt ( getValue() );

//…

return 0;

}

但是把链接指示符放在头文件中更合适在那里函数声明描述了函数的接口所属,如果我们希望C++函数能够为C 程序所用又该怎么办呢我们也可以使用extern "C"链接指示符来使C++函数为C 程序可用例如。

// 函数calc() 可以被C 程序调用

extern "C" double calc( double dparm ) { /*… */ }

如果一个函数在同一文件中不只被声明一次则链接指示符可以出现在每个声明中它,也可以只出现在函数的第一次声明中在这种情况下第二个及以后的声明都接受第一个声

明中链接指示符指定的链接规则例如

// —- myMath.h —-

extern "C" double calc( double );

// —- myMath.C —-

// 在Math.h 中的calc()的声明

#include "myMath.h"

// 定义了extern "C" calc() 函数

// calc() 可以从C 程序中被调用

double calc( double dparm ) { // …

鸟儿爱美,不仅需要羽毛之美,还需要鸣声婉转之美;

chenbaohai的专栏

相关文章:

你感兴趣的文章:

标签云: