摘要:我們都知道在C語(yǔ)言中不同類型的變量在內(nèi)存中的存放位置不同的,從內(nèi)存角度上講,不同內(nèi)存塊中存放的代碼或者變量其屬性(主要是作用域、生命周期、鏈接屬性)是不同的。首先我們介紹一下作用域、生命周期已經(jīng)鏈接屬性的概念1:作用域作用域也就是指變量其作用的范圍 (1)局部變量為代碼塊作用域(也就是說(shuō)局部變量的作用范圍是{ }) &
我們都知道在C語(yǔ)言中不同類型的變量在內(nèi)存中的存放位置不同的,從內(nèi)存角度上講,不同內(nèi)存塊中存放的代碼或者變量其屬性(主要是作用域、生命周期、鏈接屬性)是不同的。
首先我們介紹一下作用域、生命周期已經(jīng)鏈接屬性的概念
1:作用域
作用域也就是指變量其作用的范圍
(1)局部變量為代碼塊作用域(也就是說(shuō)局部變量的作用范圍是{ })
(2)函數(shù)和全局變量是文件作用域,進(jìn)一步講其作用范圍就是函數(shù)和全局變量定義或者聲明后的部分。
2:生命周期
生命周期也就是變量的產(chǎn)生時(shí)間和消亡時(shí)間
(1)棧變量的生命周期:局部變量是被分配到棧上面的(棧變量),其生命周期是臨時(shí)的,臨時(shí)的意思是按需要去創(chuàng)建、使用、消亡。比如在一個(gè)子函數(shù)里面定義了一個(gè)局部變量int a;那么當(dāng)這個(gè)子函數(shù)被調(diào)用執(zhí)行的時(shí)候,局部變量int a;會(huì)被創(chuàng)建在棧上面(符號(hào)a和棧上面的某個(gè)內(nèi)存相綁定),當(dāng)這個(gè)子函數(shù)被調(diào)用結(jié)束時(shí),局部變量int a就消亡了(取消符號(hào)a和棧上面的某個(gè)內(nèi)存的綁定),很現(xiàn)實(shí)的一個(gè)例子就是,當(dāng)我們寫(xiě)個(gè)程序去讀取局部變量的地址時(shí),每次讀取的地址值是不一樣的。
(2)堆變量的生命周期
首先需要明白一點(diǎn),堆內(nèi)存空間是客觀存在的,它是由系統(tǒng)維護(hù)的一段內(nèi)存空間,程序員只是向系統(tǒng)申請(qǐng)堆內(nèi)存,然后釋放,所以堆變量也是有生命周期的,其生命周期就是mallloc(返回申請(qǐng)堆內(nèi)存的首地址)申請(qǐng)到free釋放,
(3)數(shù)據(jù)段、bss段的生命周期
全局變量的生命周期是永久的,永久的意思是從被定義開(kāi)始,一直到程序結(jié)束。
(4)代碼段、只讀段的生命周期
代碼段存放的是程序執(zhí)行的代碼(也就是函數(shù)),它的生命周期是永久的,但是一般不去研究代碼的生命周期,需要注意的是放在代碼段的還有const修飾的常量和字符常量(const類型的常量、字符串常量有時(shí)候放在rodata段,有時(shí)候放在代碼段,取決于平臺(tái))
3:鏈接屬性
鏈接屬性是指代碼在鏈接時(shí)的屬性,包括外連接、內(nèi)鏈接、無(wú)鏈接三種
(1)外連接:意思是外部鏈接屬性,也就是說(shuō)可以在整個(gè)程序范圍(可以跨文件)內(nèi)進(jìn)行鏈接
(2)內(nèi)鏈接:意思是內(nèi)部鏈接屬性,也就是說(shuō)可以在當(dāng)前c文件范圍內(nèi)進(jìn)行鏈接
(3)無(wú)鏈接:意思是這個(gè)符號(hào)本身不參與鏈接,所有的局部變量(auto的,static的)都是無(wú)鏈接的
注意這里還涉及一個(gè)同名變量屏蔽規(guī)則的問(wèn)題
(1)問(wèn)題:編程時(shí),不可避免會(huì)出現(xiàn)同名變量。變量同名后不一定會(huì)出錯(cuò)。
(2)首先,如果兩個(gè)同名變量作用域不同且沒(méi)有交疊,這種情況下同名沒(méi)有任何影響。比如兩個(gè)子函數(shù)里面都定義了局部變量int a;
(3)其次,如果兩個(gè)同名變量作用域有交疊,C語(yǔ)言規(guī)定在作用域交疊范圍內(nèi),
作用域小的一個(gè)變量會(huì)掩蔽掉作用域大的那個(gè)(就小范圍原則)。比如定義了一個(gè)全局變量int a;又在子函數(shù)定義了局部變量int a;那么在這個(gè)子函數(shù)里面起作用的就是局部變量int a;
接下來(lái)從變量的類型角度出發(fā),分析代碼這三打要素具體到不同變量中的意義
1:普通局部變量
作用域?yàn)榇a塊作用域,生命周期為臨時(shí)性生命周期,鏈接屬性為無(wú)鏈接
普通局部變量被分配到棧上面,是按需創(chuàng)建、使用、消亡的,棧每次分配給變量是的地址是不確定的(隨機(jī)分配)這就決定了其鏈接屬性是無(wú)鏈接。
2:靜態(tài)局部變量(static修飾的局部變量)
靜態(tài)局部變量被分配到了數(shù)據(jù)段或者bss段(顯示初始化為非0則被分配到數(shù)據(jù)段,未顯式初始化或者顯式初始化為0則被分配到bss段),作用域?yàn)榇a塊作用域,生命周期為永久性生命周期,鏈接屬性為無(wú)鏈接(因?yàn)樗淖饔糜蚴谴a塊作用域)。因?yàn)殪o態(tài)局部變量被分配到了數(shù)據(jù)段或者bss段,所以它的生命周期是永久的,所分配的地址和靜態(tài)局部變量的符號(hào)的綁定是不變的,直到程序結(jié)束,所以在一個(gè)程序中多次使用同一個(gè)靜態(tài)局部變量時(shí)其實(shí)操作的是同一段內(nèi)存,因?yàn)橛羞@一特性,所以靜態(tài)局部變量常用來(lái)統(tǒng)計(jì)子函數(shù)被調(diào)用的次數(shù)。
3:全局變量和普通函數(shù)
作用域?yàn)槲募饔糜颍芷跒橛谰?,鏈接屬性為外連接
需要注意的是全局變量和函數(shù)不要在頭文件中定義,原因是一個(gè)程序多處調(diào)用這個(gè)頭文件(頭文件中的內(nèi)容在被預(yù)處理的時(shí)候是在文件中原地展開(kāi)的)時(shí)就會(huì)出現(xiàn)重復(fù)定義(當(dāng)然使用inline修飾的函數(shù)是可以放在有文件中的,并且不會(huì)城鄉(xiāng)重復(fù)定義)。全局變量的外連接屬性就決定了其必須是文件作用域以及永久的生命周期。