比較全局變量、全局靜態變量、局部變量、局部靜態變量的區別


比較全局變量、全局靜態變量、局部變量、局部靜態變量的區別,他們在編譯完后存儲位置在什么地方、初始化值在什么地方、內存什么時候分配、賦初值對這些變量有哪些影響等。要弄清楚這些問題,首先要弄清楚下面幾個知識點。

    C語言分下面幾個存儲區:

    1、棧區(stack) 由編譯器在需要的時候自動分配釋放,在不需要的時候就自動清除的變量存儲區。通常存放的變量是函數的參數值、局部變量的值等,其操作方式類似於數據結構中的棧。

    2、堆區(heap) 一般由程序員去分配釋放,和編譯器完全沒有關系,直接由我們的應用程序去控制,一般分配一塊內存就對應一個回收一塊內存。如果程序員沒有釋放掉,那么在程序結束后,操作系統會自動回收。

    3、全局(靜態存儲區) 全局變量和靜態變量的存儲是放在一塊內存中的,全局變量又分為初始化的和未初始化的。初始化的全局變量和靜態變量存儲在一塊區域內,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。程序運行結束后由系統釋放。

    4、常量存儲區這是一塊比較特殊的存儲區,他存放的是常量,不允許修改的常量。

    5、程序代碼段存放函數體的二進制代碼。  

    內存中存放數據的數據段有以下幾種:

    1、bss 是英文block started by symbol的簡稱,通常是指用來存放程序中未初始化的全局變量的一塊內存區域,在程序載入時由內核清0。bss段屬於靜態內存分配。它的初始值也是由用戶自己定義的鏈接定位文件所確定,用戶應該將它定義在可讀寫的ram區內,源程序中使用malloc分配的內存就是這一塊,它不是根據data大小確定,主要由程序中同時分配內存最大值所確定,不過如果超出了范圍,也就是分配失敗,可以等空間釋放之后再分配。

    2、text 段是程序代碼段,在at91庫中是表示程序段的大小,它是由編譯器在編譯連接時自動計算的,當你在鏈接定位文件中將該符號放置在代碼段后,那么該符號表示的值就是代碼段大小,編譯連接時,該符號所代表的值會自動代入到源程序中。

    3、data 包含靜態初始化的數據,所以有初值的全局變量和static變量在data區。段的起始位置也是由連接定位文件所確定,大小在編譯連接時自動分配,它和你的程序大小沒有關系,但和程序使用到的全局變量,常量數量相關。

    4、stack 保存函數的局部變量和參數。是一種“后進先出”(last in first out,lifo)的數據結構,這意味着最后放到棧上的數據,將會是第一個從棧上移走的數據。對於哪些暫時存儲的信息,和不需要長時間保存的信息來說,lifo這種數據結構非常理想。在調用函數或過程后,系統通常會清除棧上保存的局部變量、函數調用信息及其它的信息。棧另外一個重要的特征是,它的地址空間“向下減少”,即當棧上保存的數據越多,棧的地址就越低。棧(stack)的頂部在可讀寫的ram區的最后。

    5、heap 保存函數內部動態分配內存,是另外一種用來保存程序信息的數據結構,更准確的說是保存程序的動態變量。堆是“先進先出”(first in first out,fifo)數據結構。它只允許在堆的一端插入數據,在另一端移走數據。堆的地址空間“向上增加”,即當堆上保存的數據越多,堆的地址就越高。

 

變量可以分為全局變量、靜態全局變量、靜態局部變量和局部變量。

    按照存儲區分:全局變量、靜態全局變量和靜態局部變量都存放在內存的全局數據區,局部變量存放在內存的棧區。

    按作用域分:全局變量在整個工程文件內都有效;靜態全局變量只在定義它的文件內有效;靜態局部變量只在定義它的函數內有效,只是程序僅分配一次內存,函數返回后,該變量不會消失;局部變量在定義它的函數內有效,但是函數返回后失效。

    全局變量和靜態變量如果沒有手工初始化,則由編譯器初始化為0.局部變量的值是不可知的。靜態變量和全部變量完全是兩碼事。

    靜態變量是相對於自動變量,之所以稱為靜態變量,是說靜態變量不是隨着程序作用域的改變而銷毀,但是靜態變量的訪問受到作用域的制約。自動變量是在函數調用棧中分配的,因此隨着函數的退出,自動變量不能繼續保存原來的值。而靜態變量是在堆中分配的,編譯器會對靜態變量進行初始化,並且靜態變量在整個程序中只有一個,而不像自動變量那樣,會根據函數調用的不同具有多個副本。靜態變量的值在函數退出后不變。

    全局變量是指變量的作用域范圍是全局可見的,而變量作用域決定於變量生命的位置。就是說在所有花括號之外聲明的變量既是全局變量。

 

    各個變量的比較區別。

    從作用域看:

    全局變量和局部變量:全局變量和局部變量的區別主要在於身存周期不同,全局變量在整個程序生成期可見,局部變量在自己的作用域可見。全局變量的內存分配是靜態的,如果沒有賦初值,會被初始化為0。局部變量的內存分配是動態的,位於堆棧中,如果沒有初始化,初值視當前內存內的值而定。

    全局變量具有全局作用域。全局變量只需在一個源文件中定義,就可以作用於所有的源文件。當然,其他不包括全局變量定義的源文件需要用extern關鍵字再次聲明這個全局變量。

    靜態全局變量也具有全局作用域,他與全局變量的區別在於如果程序包含多個文件的話,他作用於定義它的文件里,不能作用到其他文件里,即被static關鍵字修飾過的變量具有文件作用域。這樣即使兩個不同的源文件都定義了相同的靜態全局變量,他們也是不同的變量。

    局部變量也只有局部作用域,他是自動對象,他在程序運行期間不是一直存在,而是只在函數執行期間存在,函數的一次調用結束后,變量就被撤銷,其所占用的內存也被收回。

    靜態局部變量具有局部作用域。它只被初始化一次,自從第一次初始化直到程序結束都一直存在,他和全局變量的區別在於全局變量對所有的函數都是可見的,而靜態局部變量只對定義自己的函數體始終可見。

int fun(int i)
{
    static int a = i;
    return a;
}
for (int i = 1; i < 10; ++i)
{
    cout << fun(i) << endl;//輸出結果總是為1
}
    

 

    從內存分配看:

    全局變量、靜態局部變量、靜態全局變量都在靜態存儲區分配空間,而局部變量在棧分配空間。

    全局變量本身就是靜態存儲方式,靜態全局變量當然也是靜態存儲方式。這兩者在存儲方式上沒有什么不同。區別在於非靜態全局變量的作用域是整個源程序,當一個源程序由多個源文件組成時,非靜態的全局變量在各個源文件中都是有效的。而靜態全局變量則限制了其作用域,即只在定義該變量的源文件內有效,在同一源程序的其他源文件中不能使用它。由於靜態全局變量的作用域局限於一個源文件內,只能為該源文件內的函數公用,因此可以避免在其他源文件中引起錯誤。

    1、靜態變量會被放在程序的靜態數據存儲區里,這樣可以在下一次調用的時候還可以保持原來的賦值。這一點是他與堆棧變量和堆變量的區別

    2、變量用static告知編譯器,自己僅僅在變量的作用域范圍內可見。這一點是他與全局變量的區別。

    從以上分析可以看出,把局部變量改變為靜態變量后是改變了他的存儲方式,即改變了他的生存期。把全局變量改變為靜態變量后是改變了他的作用域,限制了他的使用范圍,因此static這個說明符在不同的地方起的作用是不同的。

    不同類型的變量在內存中的位置:

    1、 已經初始化的全局變量存放與data數據段;未初始化的全局變量存放與bss數據段。

    2、 靜態的全局變量存放與data數據段

    3、 局部變量存放在棧上。

    4、 靜態局部變量,並不是在調用函數時分配函數返回時釋放,而是像全局變量一樣靜態分配,存放data數據段,但它的作用域在函數中起作用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM