从作用域上来说,C语言可以定义4种不同的变量:全局变量,静态全局变量,局部变量,静态局部变量。 下面仅从函数作用域的角度分析一下不同的变量,假设所有变量声明不重名。 - 全局变量,在函数外声明,例如,`int gVar;`。全局变量,所有函数共享,在任何地方出现这个变量名都是指这个变量。 除非在函数内部被重新声明定义,如下例代码。 - 静态全局变量,例如:`static sgVar;`。所有函数共享,但是这个会有编译器的限制,算是编译器提供的一种功能。 - 局部变量,例如函数/块内的`int var;`。不共享,函数的多次执行中涉及的这个变量都是相互独立的,他们只是重名的不同变量而已。 - 局部静态变量,函数中的`static int sVar;`。本函数内共享,函数的每一次执行中涉及的这个变量都是这个同一个变量。 # 全局变量 ```c int gVar = 0; // 全局变量 void gVarInr(); int main(int argc, char const *argv[]) { int gVar = 10; // 局部变量 gVarInr(); printf("gVar is %d\n",gVar); // 10 gVarInr(); printf("gVar is %d\n",gVar); // 10 return 0; } void gVarInr() { gVar++; printf("gVar is %d\n",gVar); // 1 2 } ``` 打印结果 ``` gVar is 1 gVar is 10 gVar is 2 gVar is 10 ``` # 全局静态变量 全局变量之前再冠以 static 就构成了静态的全局变量。 ## 存储方式 全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。 ## 作用域区别 这两者的区别在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。 ### 实例演示 文件1:`a.c`代码 ```c #include <stdio.h> int a = 10; ``` 文件2:`b.c`代码 ```c #include <stdio.h> extern int a; int main(int argc, char const *argv[]) { printf("%d\n", a); return 0; } ``` 在`b.c`使用 `extern` 引入`a.c`里面定义的全局变量`a`。编译 ``` $ gcc a.c b.c -o test $ ./test 10 ``` ### 修改为全局静态变量 ```diff #include <stdio.h> - int a = 10; + static int a = 10; ``` 再编译则提示 ``` $ gcc a.c b.c -o test Undefined symbols for architecture x86_64: "_a", referenced from: _main in bbb-616389.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) ``` 扩展:函数和静态函数也与之类似,函数默认是全局的,加了`static`之后,其作用域就只是本文件了。 # 局部变量 ```c #include <stdio.h> void varInr(); int main(int argc, char const *argv[]) { varInr(); varInr(); return 0; } void varInr() { int var = 0; var++; printf("var is %d\n",var); } ``` 打印结果 ```js var is 1 var is 1 ``` 这个大家都很熟悉了 # 局部静态变量 ```diff #include <stdio.h> void varInr(); int main(int argc, char const *argv[]) { varInr(); varInr(); return 0; } void varInr() { - int var = 0; + static int var = 0; var++; printf("var is %d\n",var); } ``` 打印结果 ```js var is 1 var is 2 ``` 上面几种作用域都是从函数的角度来定义作用域的,可以满足所有我们对单线程编程中变量的共享情况。 现在我们来分析一下多线程的情况。在多线程中,多个线程共享除函数调用栈之外的其他资源。 因此上面几种作用域从定义来看就变成了: - 全局变量,所有函数共享,因此所有的线程共享,不同线程中出现的不同变量都是这同一个变量。 - 静态全局变量,所有函数共享,也是所有线程共享。 - 局部变量,此函数的各次执行中涉及的这个变量没有联系,因此,也是各个线程间也是不共享的。 - 静态局部变量,本函数间共享,函数的每次执行涉及的这个变量都是同一个变量,因此是各个线程共享的。 这对我们后期的线程安全编程非常有用。http://www.php-internals.com/book/?p=chapt08/08-03-zend-thread-safe-in-php