extern关键词声明 global variable & function
In fact, function is a special global variable. 因为函数的访问也是通过全局的address实现的。
Global variable
使用extern关键词的目的是:使全局变量能在别的源文件中使用。
对于这个问题,有的人说不需要extern也能实现,例如:
/*******************************
* a.h
*******************************/
#ifndef _A_H_
#define _A_H_
int v = 1; /* define a variable */
#endif /* a.h */
/*******************************
* b.c
*******************************/
#include "a.h"
void main(void )
{
v = 10; /* update value */
}
这样做有什么问题呢?是的,如果只有一个源文件include a.h,这时貌似不会出现什么问题。
但是一旦有另一个d.c也需要用到global variable v,它也include了a.h,此时链接就会报错了
/*******************************
* d.c
*******************************/
#include "a.h"
void func(void) {
v = 20; /* also use v */
}
如果这时编译b.c和d.c,就会报multiple definition的错误。
因为两个文件在preprocess时都会展开a.h,也就相当于在源文件添加了一行 int v = 1;
的定义,那当两个obj文件链接时,肯定会发生multiple definition了。
有一点需要注意的是当a.h仅定义 int v; 没有initialize时,GCC编译器的特性是对这些obj文件中没有initialize的变量自动添加extern属性。所以要对initialize v才能观察到multiple definition的结果!
另外,如果你不是C语言的新手,大概看到过类似最好避免在header中definition的要求,header中仅declaration!这是规范C语言编程的要求。
是时候让extern出场了!
解决此问题的办法是使用v的另外源文件中用extern再次declare一次。declare可以无限次,但是define只能一次。
使用extern就无需多余的a.h了,而将global sharable variable定义在源文件a.c中,这更符合现代的应用场景。例如,上述project可以修改为:
/*******************************
* a.c
*******************************/
int v = 1; /* define a variable */
/*******************************
* b.c
*******************************/
// #include "a.h" /* no need to include a.h */
extern int v;
void main(void )
{
v = 10; /* update value */
}
/*******************************
* d.c
*******************************/
// #include "a.h" /* no need to include a.h */
extern int v;
void func(void) {
v = 20; /* also use v */
}
这个方法简直太棒了,要注意,extern int v;
仅是一个declare语句,正如上面所说,declare可以无限次!
哪个源文件需要使用v就使用extern关键词declare一次即可。
甚至,extern的作用域可以限制到function内,若在一个function内部使用extern declare一个external variable,这个全局属性仅在此function内有效!
For function
对于function,若我们想要在其它文件中调用,通常会通过包含头文件的方式。例如:
在a.c中定义了一个function add(),若要在b.c中调用,我们会通过在a.h中声明此function
/*******************************
* a.h
*******************************/
#ifndef _A_H_
#define _A_H_
int add(int x,int y);
#endif /* a.h */
然后在b.c中 include<a.h>,就可以使用add function了。
我们想过它的原理吗?
对于这种特殊的global variable,我们在header中declare它的时候其实前面省略了extern关键词!
所以其它include此header的源文件才能使用add function,大概就是这个原因。
那么,我们是不是可以这样试试:
/*******************************
* a.c
*******************************/
int add(int x,int y)
{
return x + y;
}
/*******************************
* b.c
*******************************/
// #include "a.h"
extern int add(int x, int y);
void main(void )
{
printf("%d\r\n", add(1, 2));
}
哈哈,按照原理来说,当然也是可以的,这也就表示function和global variable本质上是类似的。
However,在实际应用中我们很少这样用,因为一旦需要调用的函数很多,很难去一下子梳理每个函数来自哪个源文件(lll¬ω¬),不仅仅你过几天会忘记这些函数来自哪个源文件,对于接手此项目的下一位coder,这更是一场disaster!