《linux c程式設計 王者歸來》這門課程的第三章是函式,函式的作用就是使得程式的模組性更強,不同作用的函式放在不同的地方,更重要的就是便於**的修改和閱讀。
學習函式首先要了解函式的本質,函式的本質是一段機器指令**。而函式名的本質就是乙個標號,該標號的值等於記憶體中儲存函式**的首位址。函式呼叫時會使空間的棧不斷增長,從當前程序中的棧頂的位置到函式儲存返回值的位置,這一塊記憶體成為函式的棧幀。所有函式中定義的區域性變數都儲存在函式的棧幀上,當函式呼叫結束的時該塊棧幀就消失了。如下圖所示:
呼叫者函式開始呼叫之後,函式棧幀開始生長,呼叫完畢,該棧幀消失。一般地函式呼叫分為4個步驟:
將引數壓入棧堆
儲存暫存器的值
儲存返回位址
跳轉這四步中的前三步都要訪問記憶體,訪問內存在計算機操作中很消耗時間,因此,函式呼叫比較好費時間,程式執行時應儘量減少函式的呼叫,對程式起到一定的優化作用。
從上圖函式的本質中可以看出,c語言程式中的區域性變數儲存在棧上,全域性變數儲存在資料段上,也就是記憶體中。因為全域性變數在整個程式的執行過程中一直存在,如果存在暫存器中會降低程式的執行效率。之前也提到過,儘量減少記憶體訪問能夠很大的提高程式的效率。區域性變數會儲存在暫存器中,因此一種程式的優化方式就是不要將迴圈運算元等高頻率使用的變數設定為全域性變數或者靜態變數。例如下邊兩個函式a.c和b.c:
a.c:
1b.c:inti;23
void
f()4
5
1從上邊的兩個程式對比可以看出,迴圈運算元是i的程式中,每次訪問全域性變數的時候都要從記憶體中去資料。每次呼叫全域性變數都要經過從記憶體中讀取變數i的值,對變數i進行累加,將變數i的值重新存回到記憶體中這三步,而拒不變數只需要做累加變數所在的暫存器的值,從這兩個簡單程式的對比就能看出區域性變數的執行效率要比全域性變數高的多,如果要進行多次訪問的話盡量採用區域性變數。void
f()2
3
函式作用就是使得程式的模組性更強,為了能夠使程式模組化更強,**易於管理,需要將同一型別的**放在乙個檔案中,這樣將**分為若干個模組放在不同的檔案中,在呼叫和編譯的時候需要從不同的檔案中去呼叫函式,這就會導致多個c語言檔案鏈結的問題。鏈結中經常會發生會出現的就是乙個檔案可能需要引用另乙個檔案中定義的全域性變數或者函式。在這一章講了鏈結時符號的解析規則,這是最基本的但是容易被忽略的東西。
在c語言中,宣告和定義是有區別的,宣告只需要告知編譯器變數的存在,不需要分配儲存空間,例如:
定義不僅要告訴編譯器變數的存在還有為變數分配儲存空間,例如:
int a=1;
但是,當乙個變數在作用域範圍內只有宣告,沒有定義時,編譯器會自動將第乙個宣告認定為變數的定義,下面我們來看c語言中的符號解析規則。
規則1:不允許有多個對同一變數或者函式的定義。
比如a.c中函式為:
1b.c中的函式為:int a=123;2
3int main(void)4
5
1這兩個函式在進行鏈結的時候會出現錯誤,連個檔案中都對同乙個函式main()進行了定義,而且他們還對同乙個變數進行了定義,這兩條都違反了規定一,因此在呼叫的時候會出粗。int a=121;2
3int main(void)4
5
規則2:如果有乙個符號定義和多個符號的宣告,則選擇被定義的符號。
比如兩個函式a.c和b.c:
兩個檔案中都對a進行了定義和宣告,執行結果如下圖所示,當出現乙個變數定義和多個變數宣告的時候應該要符合規則2,選擇變數的定義。所以這個程式中全域性變數a在f()中被修改為121,結果儲存在全域性變數a的儲存空間中。
規則3:如果有多個字元的宣告,則從其中任選乙個作為符號的定義。
這個程式中有a的定義和a的宣告,根據解析規則2是不會造成鏈結錯誤的,根據規則2我們知道b.c程式中對於a的操作實際是對a.c中的全域性變數a進行操作的。但是在b.c中的宣告的變數是雙精度的,雙精度的變數是8個位元組,整型的數字是4個位元組。因此a在進行賦值之後會把b的空間也佔掉就會出現下面的錯誤顯示。
書上的程式是b.c中賦值為0.0列印出來之後最後a,b的值都為0,解釋為將8個位元組都清0了。後來我處於好奇覺得如果賦值為其他的數字,比如3.5會不會顯示成a=3,b=5。然後改完程式發現,a列印整數顯示0,b列印整數顯示為1074528256。緊接著我去查了double型別數字在機內的指數形式表示分為四部分,數符,尾數,指數符,指數四個部分,double型別數字數符加尾數佔48位,指數符加指數佔16位。因此,會出現亂碼這種情況,至於具體的為什麼產生的是0和1074528256,我覺得肯定是可以算出來為什麼的,但是具體數符,尾數,指數符,指數是怎麼儲存的,佔多少位我還不清楚,接下來有時間時的話會去算一算,深究一下。
總結這幾天的學習來說,學習程式設計,主要還是在於實踐,一定要敲**。我在部落格中舉的例子一般都是我第一次看書的時候沒有完全理解的東西,有些話說的很簡單,看似理解其實並沒有理解,只是理解了字面意思,甚至來說書上的例子都不能夠完全幫助你去理解。每次遇到這些不懂得東西,我都會把書上的例子敲出來,執行然後去理解,不知道為什麼的話去修改一下引數,加斷點去除錯去看,這樣能夠比較好的理解。在看書和敲書上**的時候要多問一下為什麼看看能不能自己去解答,通過改**編譯實現來驗證自己的解答,如果正確那說明自己理解的沒有問題,如果錯誤那就要找到錯在哪,最終才能真正的理解。
第一周學習總結
第一周,我們有學習,計算機的發展,起源,計算機的各種進化,還有計算機的概念,計算機的語言,計算機的組成這些等等。讓我深刻的意識到這是很龐大的一門課程,同時也對我們接下來要學習的課程充滿了期待。對於我自己來說,第一周的學習我還是覺得挺不錯的,挺開心的,能認識到這麼多的朋友,這麼多的知識,讓我對計算機有...
第一周學習總結
第一周總結 今天 2018.11.22 我們班開了一次班會,這次班會主要是由我主持的,在班會上,我先交代了最近班級需要注意的問題和需要完成的工作,在會議的最後我還著重強調了班級班風的建設問題。身為我們班的團支書,我感覺我身上擔負的責任很重,我也在盡心盡力的為班級建設做貢獻。最重要的,這些責任更是對我...
第一周學習總結
第一周的學習大部分都是概念性的理論講解,之前第一篇部落格已經談到了部分概念剩下的概念有 1.測試相關概念 it information technology 資訊科技和產業 軟體 一系列按照特定順序組織的計算機資料和指令的集合 程式 資料 檔案 產品 能夠供給市場,被人們使用和消費,並能滿足人們某種...