我们在学习全局变量的时候,常说全局变量可以在外部访问,只要在外部加上extern关键字声明,即可使用,而如果这个全局变量加上了static关键字修饰,即变成了【静态全局变量】的时候,外部则无法访问了,但很多人在尝试的时候会发现,外部竟然也可以访问,甚至不加extern关键字都能访问到。
原因是:使用了不正确include,并理解错了“外部”的含义。
下面以linux环境举例说明,假设两个文件v1.c和v2.c,v2.c中包含一个全局变量a,v1中使用extern关键字使用这个a,应该写如下代码:
// v1.c
#include <stdio.h>
int main() {
extern int a;
printf("extern int a = %d\n", a);
return 0;
}
// v2.c
#include <stdio.h>
int a = 100;
static int b = 101;
如果在v1.c中写了#include "v2.c",那么v2.c会被当成v1.c的一部分,此时虽不在同一个源文件中,但二者仍像在同一个文件中一样,是不能称为“外部”的。必须像如上这种不存在直接include关系的情形,才能称为“外部”。但以上代码如何编译并运行?此处使用gcc来操作:
gcc -c v1.c v2.c # 编译产生v1.o v2.o
gcc v1.o v2.o -o vmain # 将v1.o和v2.o经过链接成可执行文件vmain
./vmain # 执行vmain
执行后得到结果:
[yancy@localhost test]$ gcc -c v1.c v2.c
[yancy@localhost test]$ gcc v1.c v2.c -o vmain
[yancy@localhost test]$ ./vmain
extern int a = 100
[yancy@localhost test]$
以上才是正确的引用外部全局变量的方法。
而用这种方法,在v1.c中引用v2.c中定义的static全局变量:
#include <stdio.h>
int main() {
extern int a; // 引用外部的全局变量a
printf("extern int a = %d\n", a);
extern int b; // 试图引用外部的静态全局变量b
printf("extern int b = %d\n", b);
return 0;
}
则会在链接环节报错:
[yancy@localhost test]$ gcc -c v1.c v2.c
[yancy@localhost test]$ gcc v1.c v2.c -o vmain
/tmp/ccGRMlxv.o: In function `main':
v1.c:(.text+0x1d): undefined reference to `b'
collect2: error: ld returned 1 exit status
[yancy@localhost test]$
这也证实了,static全局变量无法在外部被使用。
这里的【外部】,实际上是【单独编译的模块外部】,就是这里gcc -c形成的.o文件,每一个.o文件是一个单独的模块,所以不能以【源文件】外部为准,是站在编译角度来说的。当初刚学C语言的时候,并不理解编译、链接等内容,导致这个问题一直没懂,希望这里能帮大家解惑。