static變量放在函數中,就只有這個函數能訪問它; 放在函數外就只有這個文件能訪問它。 下面我們看看兩個函數中重名的static變量是怎麼區別開來的 (static.c):
#include <stdio.h>
void func1()
{
static int n = 1;
n++;
}
void func2()
{
static int n = 2;
n++;
}
int main()
{
return 0;
}
下面是編譯後的部分彙編:
func1:
pushl %ebp
movl %esp, %ebp
movl n.1671, %eax
addl $1, %eax
movl %eax, n.1671
popl %ebp
ret
func2:
pushl %ebp
movl %esp, %ebp
movl n.1674, %eax
addl $1, %eax
movl %eax, n.1674
popl %ebp
ret
好傢伙!編譯器居然"偷偷"地改了變量名, 這樣兩個static變量就容易區分了。
其實static變量跟全局變量一樣被放置在 .data段 或 .bss段 中,所以它們也是程序運行期間一直存在的, 最終也是通過絕對地址來訪問。 但是它們的作用域還是比全局變量低了一級: static變量被標識為LOCAL符號,全局變量被標識為GLOBAL符號, 在鏈接過程中,目標文件尋找外部變量時只在GLOBAL符號中找, 所以static變量別的源文件是"看不見"的。
作用域控制為的是提高源代碼的可讀性, 一個變量的作用域越小,它可能出沒的範圍就越小。
C語言中的變量按作用域從大到小可分為四種: 全局變量、函數外static變量、函數內static變量、局部變量:
顯然,作用域越小越省心, 該是局部變量的就不要定義成全局變量, 如果"全局變量"只在本源文件中使用那就加個static。
即便是局部變量也還可以壓縮其作用域:
有的同學寫的函數一開頭就聲明瞭函數中要用到的所有局部變量, 一開始我也這麼做,因為我擔心:如果把變量定義在循環體內, 是不是每一次循環都會給它們分配空間、回收空間,從而降低效率? 但事實是它們的空間在函數的開頭就一次性分配好了(scope.c):
#include <stdio.h>
int main()
{
int a = 1;
{
int a = 2;
{
int a = 3;
}
{
int a = 4;
}
}
return 0;
}
編譯後的彙編代碼如下:
main:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $1, -4(%ebp)
movl $2, -8(%ebp)
movl $3, -12(%ebp)
movl $4, -16(%ebp)
movl $0, %eax
leave
ret
各層局部環境中的變量a是subl $16, %esp一次性分配好的。 由此可見不是每個{}都要分配回收局部變量, 一個函數只分配回收一次。因此, 如果某個變量只在某個條件、循環中用到的話, 還是在條件、循環中定義吧,這樣, 規模比較大的函數的可讀性將提高不少,而效率絲毫沒有下降, 可謂是百利而無一害!