C語言中,存儲類別(Storage Class)是一個標識符(也就是說函數和變量)的重要屬性。存儲類別決定著一個函數或變量的作用域(Scope,即可見性)和生命周期(Life time)。C語言中,主要有四種存儲類別,即auto、register、static和extern,下面將一一說明。
在說明之前,先講清楚幾個概念:
(1) 定義(Definition)和聲明(Declaration)
聲明是通知編譯器變量的名字(name),類型(type),作用域(scope),鏈接性(linkage)和變量的聲明周期(Duration or Lifetime);而變量的定義會導致編譯器給該變量分配內存。需要注意的是只能在變量定義的時候對其進行初始化。因為,只有變量的定義才導致內存分配才需要初始化,變量聲明是聲明的一塊已經分配好的內存空間,該空間在變量定義的時候已經被初始化過。
(2)作用域(scope)
作用域是一個編譯時概念,主要有兩種:文件(file)和塊(block)。文件作用域是指從變量的聲明到文件的末尾,該變量都是可以訪問的;塊作用域是指從變量被聲明到改程序塊的末尾是可以被訪問的。
(3)鏈接性(linkage)
在C語言中,大體來說,有兩種類型的對象(這裡不是指面向對象編程中的對象,只是一般意義上的對象,也可以理解為元素)外部對象和內部對象(External和Internal,也就是上面的連接性)。所有在函數外聲明的對象都是外部的,包括函數(函數也必須在函數外定義,因此,這很容易理解);所有在函數內部的對象都是內部的,包括函數的參數。從這種意義上來說,C語言程序是由外部對象的集合構成的。只有外部對象能夠參與跨文件和代碼庫之間的通訊。
鏈接性是一個鏈接時概念,用來定義對象是否能被跨文件訪問,或者只能在一個文件中訪問,主要有三種:外部(External),內部(Internal)和No Linkage。函數內部的任何對象,包括參數,變量和其它都是no linkage,因此它們只能夠從函數內部被訪問(當然,如果在函數內部用extern作前綴聲明了一個對象,這就是說,它不是no linkage的,這裡先不討論這種情況);具有外部鏈接性的對象必須在程序的最外層(也就是說不能夠在函數或語句塊內部),外部鏈接性也是在函數外聲明的函數或其它對象的默認鏈接性,所有名字相同的具有外部鏈接性的實例都是引用的程序中的同一對象(也就是說內存中的同一區域);當希望函數或其它對象只能夠在一個文件內被訪問,而不能被文件外訪問時,應該使這種對象具有內部鏈接性,相同名字的具有內部連接性的對象只在同一個文件內引用的是同一個對象,通過在對象的聲明前加static關鍵字可以將外部對象的鏈接性聲明為內部鏈接性(當然,也可以在局部變量前加static,意義和這裡不一樣)。
外部鏈接性是指該變量能夠被多個文件訪問;內部鏈接性是指該變量只能夠在被聲明的文件中被訪問。
(4)聲明周期(duration)
變量的聲明周期是一個運行時概念,主要有兩種Temporary和Process。Temporary的變量只在函數或代碼塊執行的時候存在,這類變量存儲在棧(stack)中;Process變量在程序運行的整個過程中都會存在,這類變量存儲在內存中的靜態存儲區。
1、auto
局部變量的缺省存儲類別是auto,也就是說,下面兩個變量的定義在存儲類別層面對編譯器來說是一樣的。
{
int life;
auto int love;
}
存儲類別為auto類型的標識符只能用在函數內部,比如做局部變量。其實,這是一種節省內存的方法,因為存儲類別為auto的變量只在需要的時候才存在:當程序進入了它們所在的函數中時才會創建它們,而當退出這個函數時,它們也會隨之被銷毀。
2、register
register存儲類別用來定義應該被存儲在寄存器而非內存的變量。這樣,一個存儲類別為register的變量的最大不能超過寄存器的存儲空間(通常是一個字長),並且register類型的變量不能用一元的&運算符來(也就是取地址操作符)操作。(很容易理解,因為register類型的變量是存儲在寄存器,而非內存,所以不能用&來取它的內存地址。)。通常,register類型的變量通常用於經常被訪問的變量,比如計數器。
{
register int counter;
}
當然,也要知道,register說明符只是建議編譯器將該變量存儲到寄存器中,但是,在實際中,編譯器並不一定會這樣做(比如,可能沒有足夠數量的寄存器供編譯器使用)。實際上,現在性能優越的編譯器能夠識別出經常使用的變量,並將其放在寄存器中,而無需程序員給出register聲明。
更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2013-11/92235p2.htm