extern关键词声明 global variable & function

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的结果!

参考:https://www.cnblogs.com/Sorean/p/4709039.html


另外,如果你不是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!

上一篇:stm32cubemx使用AHT10


下一篇:extern总结