歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C語言之從內存角度理解不同類型的變量

C語言之從內存角度理解不同類型的變量

日期:2017/3/1 9:09:57   编辑:Linux編程

我們都知道在C語言中不同類型的變量在內存中的存放位置不同的,從內存角度上講,不同內存塊中存放的代碼或者變量其屬性(主要是作用域、生命周期、鏈接屬性)是不同的。

首先我們介紹一下作用域、生命周期已經鏈接屬性的概念

1:作用域

作用域也就是指變量其作用的范圍

(1)局部變量為代碼塊作用域(也就是說局部變量的作用范圍是{ })

(2)函數和全局變量是文件作用域,進一步講其作用范圍就是函數和全局變量定義或者聲明後的部分。

2:生命周期

生命周期也就是變量的產生時間和消亡時間

(1)棧變量的生命周期:局部變量是被分配到棧上面的(棧變量),其生命周期是臨時的,臨時的意思是按需要去創建、使用、消亡。比如在一個子函數裡面定義了一個局部變量int a;那麼當這個子函數被調用執行的時候,局部變量int a;會被創建在棧上面(符號a和棧上面的某個內存相綁定),當這個子函數被調用結束時,局部變量int a就消亡了(取消符號a和棧上面的某個內存的綁定),很現實的一個例子就是,當我們寫個程序去讀取局部變量的地址時,每次讀取的地址值是不一樣的。

(2)堆變量的生命周期

首先需要明白一點,堆內存空間是客觀存在的,它是由系統維護的一段內存空間,程序員只是向系統申請堆內存,然後釋放,所以堆變量也是有生命周期的,其生命周期就是mallloc(返回申請堆內存的首地址)申請到free釋放,

(3)數據段、bss段的生命周期

全局變量的生命周期是永久的,永久的意思是從被定義開始,一直到程序結束。

(4)代碼段、只讀段的生命周期

代碼段存放的是程序執行的代碼(也就是函數),它的生命周期是永久的,但是一般不去研究代碼的生命周期,需要注意的是放在代碼段的還有const修飾的常量和字符常量(const類型的常量、字符串常量有時候放在rodata段,有時候放在代碼段,取決於平台)

3:鏈接屬性

鏈接屬性是指代碼在鏈接時的屬性,包括外連接、內鏈接、無鏈接三種

(1)外連接:意思是外部鏈接屬性,也就是說可以在整個程序范圍(可以跨文件)內進行鏈接

(2)內鏈接:意思是內部鏈接屬性,也就是說可以在當前c文件范圍內進行鏈接

(3)無鏈接:意思是這個符號本身不參與鏈接,所有的局部變量(auto的,static的)都是無鏈接的

注意這裡還涉及一個同名變量屏蔽規則的問題

(1)問題:編程時,不可避免會出現同名變量。變量同名後不一定會出錯。

(2)首先,如果兩個同名變量作用域不同且沒有交疊,這種情況下同名沒有任何影響。比如兩個子函數裡面都定義了局部變量int a;

(3)其次,如果兩個同名變量作用域有交疊,C語言規定在作用域交疊范圍內,

作用域小的一個變量會掩蔽掉作用域大的那個(就小范圍原則)。比如定義了一個全局變量int a;又在子函數定義了局部變量int a;那麼在這個子函數裡面起作用的就是局部變量int a;

接下來從變量的類型角度出發,分析代碼這三打要素具體到不同變量中的意義

1:普通局部變量

作用域為代碼塊作用域,生命周期為臨時性生命周期,鏈接屬性為無鏈接

普通局部變量被分配到棧上面,是按需創建、使用、消亡的,棧每次分配給變量是的地址是不確定的(隨機分配)這就決定了其鏈接屬性是無鏈接。

2:靜態局部變量(static修飾的局部變量)

靜態局部變量被分配到了數據段或者bss段(顯示初始化為非0則被分配到數據段,未顯式初始化或者顯式初始化為0則被分配到bss段),作用域為代碼塊作用域,生命周期為永久性生命周期,鏈接屬性為無鏈接(因為它的作用域是代碼塊作用域)。因為靜態局部變量被分配到了數據段或者bss段,所以它的生命周期是永久的,所分配的地址和靜態局部變量的符號的綁定是不變的,直到程序結束,所以在一個程序中多次使用同一個靜態局部變量時其實操作的是同一段內存,因為有這一特性,所以靜態局部變量常用來統計子函數被調用的次數。

3:全局變量和普通函數

作用域為文件作用域,生命周期為永久,鏈接屬性為外連接

需要注意的是全局變量和函數不要在頭文件中定義,原因是一個程序多處調用這個頭文件(頭文件中的內容在被預處理的時候是在文件中原地展開的)時就會出現重復定義(當然使用inline修飾的函數是可以放在有文件中的,並且不會城鄉重復定義)。全局變量的外連接屬性就決定了其必須是文件作用域以及永久的生命周期。

Copyright © Linux教程網 All Rights Reserved