從作用域上來說,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