補充:
(1)儲存類就是儲存型別,也就是描述c語言變數在何種地方儲存。
(2)記憶體有多種管理方法:棧、堆、資料段、bss段、.text段(**段)……乙個變數的儲存類屬性就是描述這個變數儲存在何種記憶體段中。
(1)作用域是描述這個變數起作用的**範圍。
(2)基本來說,c語言變數的作用域規則是**塊作用域。
(1)生命週期是描述這個變數什麼時候誕生(執行時分配記憶體空間給這個變數)及什麼時候死亡(執行時收回這個記憶體空間,此後再不能訪問這個記憶體位址,或者訪問這個記憶體位址已經和這個變數無關了)的。
(2)變數和記憶體的關係,就和人(變數)去圖書館借書(記憶體)一樣。變數的生命週期就好象我人借書的這段週期一樣。
(3)研究變數的生命週期可以我們理解程式執行的一些現象、理解c語言的一些規則。
(2).o的目標檔案鏈結生成最終可執行程式的時候,其實就是把符號和相對應的段給鏈結起來。
(1)c語言程式執行時環境有一定要求
(2)arm裸機第十六部分,寫shell時有一次定義了乙個全域性變數初始化為0但是實際不為0,後來在裸機的start.s中加了清bss段**就變0了。
(3)資料段的全域性變數或靜態區域性變數都是有非0的初值的,這些初值在main函式執行之前就已經被初始化了,是重定位期間完成的初始化。
(1)static的第一種用法是:用來修飾區域性變數,形成靜態區域性變數。
(2)static的第二種用法是:用來修飾全域性變數,形成靜態全域性變數。
(1)register修飾的變數。編譯器會盡量將它分配在暫存器中(平時分配的一般的變數都是在記憶體中的)
(2)uboot中用到了乙個register型別的變數gd
(3)平時寫**要被定義成register這種情況很少,一般慎用。
(4)register編譯器只能承諾盡量將register修飾的變數放在暫存器中,但是不保證一定放在暫存器中。主要原因是因為暫存器數量有限,不一定有空用。
(1)extern主要用來宣告全域性變數,宣告的目的主要是在a.c中定義全域性變數而在b.c中使用該變數。
(1)c語言中volatile用來修飾乙個變數,表示這個變數可以被編譯器之外的東西改變。
(2)編譯器的優化在一般情況下非常好,可以幫助提公升程式效率。但是在特殊情況(volatile)下,變數會被編譯器想象之外的力量所改變,此時如果編譯器沒有意識到而去優化則就會造成優化錯誤,優化錯誤就會帶來執行時錯誤。而且這種錯誤很難被發現。
(3)volatile是程式設計師意識到需要volatile然後在定義變數時加上volatile,如果你遇到了應該加volatile的情況而沒有加程式可能會被錯誤的優化。如果在不應該加volatile而加了的情況程式不會出錯只是會降低效率。所以我們對於volatile的態度應該是:正確區分,該加的時候加不該加的時候不加,如果不能確定該不該加為了保險起見就加上。
(1)c99中才支援的,所以很多延續c89的編譯器是不支援restrict關鍵字,gcc支援的。
(2)restrict也是和編譯器行為特徵有關的。
(3)restrict只用來修飾指標,不能修飾普通變數。
(4)(5)memcpy和memmove的區別
(1)因為函式和全域性變數是外部鏈結屬性,就是說每乙個函式和全域性變數將來在整個程式中所有的c檔案都能被訪問,因此在乙個程式中的所有c檔案中不能出現同名的函式/同名的全域性變數。
(2)最簡單的解決方案就是起名字不要重複,但是很難做到。主要原因是乙個很大的工程中函式和全域性變數名字太多了,而且乙個大工程不是乙個人完成的,是很多人協作完成,所以很難保證不會重名。解決方案呢?
(3)現代高階語言中完美解決這個問題的方法是命名空間namespace(其實就是給乙個變數帶上各個級別的字首)。但是c語言不是這麼解決的。
1、普通(自動)區域性變數分配在棧上,作用域為**塊作用域,生命週期是臨時,連線屬性為無連線。定義時如果未顯式初始化則其值隨機,變數位址由執行時在棧上分配得到,多次執行時位址不一定相同,函式不能返回該類變數的位址(指標)作為返回值。
2、靜態區域性變數分配在資料段/bss段(顯式初始化為非0則在資料段,顯式初始化為0或未顯示初始化則在bss段),作用域為**塊作用域(人為規定的),生命週期為永久(天然的),鏈結屬性為無連線(天然的)。定義時如果未顯式初始化則其值為0(天然的),變數位址由執行時環境在引導程式時確定,整個程式執行過程中唯一不變;靜態區域性變數其實就是作用域為**塊作用域(同時鏈結屬性為無連線)的全域性變數。靜態區域性變數可以改為用全域性變數實現(程式中盡量避免用全域性變數,因為會破壞結構性)。
3、靜態全域性變數/靜態函式和普通全域性變數/普通函式的唯一差別是:static使全域性變數/函式的鏈結屬性由外部鏈結(整個程式所有檔案範圍)轉為內部鏈結(當前c檔案內)。這是為了解決全域性變數/函式的重名問題(c語言沒有命名空間namespace的概念,因此在程式中檔案變多之後全域性變數/函式的重名問題非常嚴重,將不必要被其他檔案引用的全域性變數/函式宣告為static可以很大程度上改善重名問題,但是仍未徹底解決)。
4、寫程式盡量避免使用全域性變數,尤其是非static型別的全域性變數。能確定不會被其他檔案引用的全域性變數一定要static修飾。
5、注意區分全域性變數的定義和宣告。一般規律如下:如果定義的同時有初始化則一定會被認為是定義;如果只是定義而沒有初始化則有可能被編譯器認為是定義,也可能被認為是宣告,要具體分析;如果使用extern則肯定會被認為是宣告(實際上使用extern也可以有定義,實際上加extern就是明確宣告這個變數為外部鏈結屬性)。
6、全域性變數應該定義在c檔案中並且在標頭檔案中宣告,而不要定義在標頭檔案中(因為如果定義在標頭檔案中,則該標頭檔案被多個c檔案包含時該全域性變數會重複定義)。
7、在b.c中引用a.c中定義的全域性變數/函式有2種方法:一是在a.h中宣告該函式/全域性變數,然後在b.c中#include ;二是在b.c中使用extern顯式宣告要引用的函式/全域性變數。其中第一種方法比較正式。
8、儲存類決定生命週期,作用域決定鏈結屬性。
9、巨集和inline函式的鏈結屬性為無連線。
儲存類 作用域 生命週期 鏈結屬性
含義 描述變數空間開闢於記憶體中什麼地方,記憶體被分為棧 堆 資料段 bss段 text段等管理方法的記憶體段,變數空間開闢於這些段中。如區域性變數 棧 被顯示初始化為非0的全域性變數和被初始化為非0的static區域性變數 data段 顯示初始化為0和沒有顯示初始化的全域性變數 bss段 int ...
儲存類 作用域 生命週期 鏈結屬性
儲存類,就是儲存型別。用於描述變數空間開闢於記憶體中的什麼地方。儲存類相關的關鍵字 相同之處 靜態區域性變數在儲存類方面 資料段 生命週期方面和全域性變數一樣。不同之處 作用域 鏈結屬性不同。靜態區域性變數作用域是 塊作用域 和自動區域性變數一樣 鏈結屬性是無連線 全域性變數作用域是檔案作用域 和函...
C語言的儲存類 生命週期 作用域 鏈結屬性
關鍵字 auto register extern static 一 儲存類 變數的儲存型別。1 記憶體被分成 棧 堆 資料段 bss段 和text段等不同管理方法的記憶體段。區域性變數被分配與棧中。他的儲存類就是棧。2 被顯式初始化為非0的全域性變數分配在data段。那麼該全域性變數的 儲存類就是d...