1. 程式人生 > >C語言中符號的儲存類、連結屬性和生命週期

C語言中符號的儲存類、連結屬性和生命週期

C語言中符號的儲存類
程式碼段:程式執行的程式碼,其實就是函式,它的生命週期是永久的(永久的意思就是在程式被執行時誕生,在程式終止時消亡),不過一般程式碼的生命週期我們並不關注。有時候放在程式碼段的不只是程式碼,還有const型別的常量,還有字串常量(const型別的常量、字串常量有時候放在只讀資料段,有時候放在程式碼段,取決於平臺)。linux中程式碼段又叫文字段(.text)。
資料段:顯式初始化為非0的全域性變數和static區域性變數存在資料段
bss段:顯式初始化為0或者未顯式初始化的全域性變數和static區域性變數存在bss段(static區域性變數可以在資料段/bss段上)。

:C語言不會自動向堆中存放東西,堆記憶體空間是客觀存在的,是由作業系統維護的。堆記憶體在使用的時候malloc/alloc/realloc申請然後使用然後free釋放。堆記憶體在malloc之前和free之後不能再去訪問。
這裡要注意:用malloc函式向系統堆管理器申請記憶體時返回值是一個指標,這個指標指向申請的那段記憶體。由於malloc剛申請的這段記憶體時尚未用來儲存資料並且也無法預知這段記憶體將來被存放什麼型別的資料,所以就返回一個void *型別,在malloc之後可以給這段記憶體讀寫任意型別的資料。(void型別平時使用時一般都是用void *指標,而不是僅僅使用void。void型別的最終歸宿,就是被強制型別轉換成一個具體型別)
:普通區域性變數分配在棧上,這也是函式不能返回普通區域性變數的地址(指標)作為返回值得原因,另外函式呼叫傳參過程也會用到棧。
只讀資料段:const修飾的常量有可能是存在只讀資料段的,但是不一定,因為const常量的實現方法在不同平臺是不一樣的。

C語言中的符號有三種連結屬性
外連線的意思就是外部連結屬性,也就是說可以在整個程式範圍內(可以跨檔案)進行連結,譬如普通的函式和無static修飾的全域性變數屬於外連線。
內連結的意思就是(c檔案內部)內部連結屬性,也就是說這傢伙可以在當前c檔案內部範圍內進行連結(言下之意就是不能在當前c檔案外面的其他c檔案中進行訪問、連結)。static修飾的函式/全域性變數屬於內連結。
無連線

的意思就是這個符號本身不參與連結,它跟連結沒關係。所有的區域性變數(auto的、static的)都是無連線的。
由連結屬性引起的函式/變數同名問題
(1)因為普通的函式和無static修飾的全域性變數具有外部連結屬性,就是說每一個函式和全域性變數將來在整個程式中所有的c檔案都能被訪問,因此在一個專案中的所有c檔案中不能出現同名的函式/同名的全域性變數。
(2)可以將明顯不會在其他c檔案中引用(只在當前c檔案中引用)的函式/全域性變數,使用static修飾使其成為內連結屬性,這樣在將來連線時即使2個c檔案中有重名的函式/全域性變數,只要其中一個或2個為內連結屬性就沒事。
(3)另外寫程式儘量避免使用全域性變數,尤其是非static型別的全域性變數。能確定不會被其他檔案引用的全域性變數一定要static修飾。
(4)這種解決方案在一定程度上解決了問題。但是,留下了很多麻煩,這就導致了用C語言作大型專案的開發語言難度很大。寫到這裡筆者也不得不感慨Linux核心的偉大,再次向那些大神致敬!

綜上得出的一些小結論
儲存類決定生命週期,作用域決定連結屬性;
靜態區域性變數在儲存類和生命週期方面和全域性變數一樣,區別是:靜態區域性變數作用域是程式碼塊作用域(和普通區域性變數是一樣的)、連結屬性是無連線;全域性變數作用域是檔案作用域(和函式是一樣的)、連結屬性方面是外連線。

另外在C語言中extern主要用來宣告全域性變數,宣告的目的主要是在當前.c檔案中定義全域性變數而在另一個.c檔案中使用該變數。