文章目錄
- 一、函數的聲明和定義
- 1.1 單個文件
- 1.2 多個文件
- 1.3 static和extern
- 1.3.1 static修飾局部變量
- 1.3.2 static修飾全局變量
- 1.3.3 static修飾函數
- 總結
一、函數的聲明和定義
1.1 單個文件
一般我們在使用函數的時候,直接將函數寫出來就使用了
題目:寫一個函數判斷一年是否是閏年
圖中4-10行是函數的定義,16行這里是函數的調用,在這種場景下,函數的定義在函數的調用之前,沒啥問題。
而在另一個場景下,當我們需要把函數的定義放在函數的調用后邊,因為編譯器是從前mian的函數往后處理代碼的,當調用函數的時候,編譯器不知道這是個什么東西,就會報警告了。
怎么解決呢?那就是在前面告訴編譯器一聲,有這么個函數,這就叫函數的聲明,
聲明函數只要交代清楚:函數名,函數的返回類型和函數的參數。
如:int is_leap_year(int y);
函數聲明中參數只保留類型,省略名字也是可以的(即y),因為聲明中的y不會用到,定義里才用得到。
代碼變成這樣就可以正常編譯了
有的兄弟就要問了,你前面雖然把函數的定義放到前面了,但也沒有聲明呀。
那是因為函數的定義是一種特殊的聲明。
1.2 多個文件
一般在企業中寫代碼的時候,代碼可能比較多,有個幾w行,不會將所有的代碼都放到一個文件里,往往會根據程序的功能,把代碼拆分到多個文件里,這里很好理解,比如說有30個程序員,難道要他們在一個文件里寫代碼嗎,難不成還要分前后順序?就算給共享文檔也會出現問題,而且每個人都要看前一個人寫的代碼,讀起來也費勁,這不符合互相協調和模塊化程序了
一般情況下,函數的聲明、類型的聲明放在頭文件(add.h)中,函數的定義放在(add.c),函數的實現放在源文件(test_05_30_01.c)中,例如這樣:
這里是點擊名字,進行拖拉,把三個文件放在一個窗口上看的。
補充:因為是在不同的文件中,在源文件中想要實現函數需要包含頭文件,因為文件時自己創建的,不是標準庫里提供的,所以包含的樣式有所區別:
#include"add.h"
使用雙引號就可以了。
稍作對比就可以發現,庫函數和這里的原理是對應的。
當然add.c不用必須與add.h的名字一樣,這里之所以一樣只是為了對應起來更加直觀,其他地方調用也只要包含對應的頭文件就可以了。
這樣多文件的形式就達到了以下兩種效果
- 方便模塊化編程
- 方便協作
比如現在讓5個程序員來寫一個計算器程序,這個計算機的程序可以分為4個大塊
- 加法
- 減法
- 乘法
- 除法
A B C D E
add.c sub.c mul.c div.c test.c
add.h sub.h mul.h div.h #include"add.h"#include"sub.h"......
這樣每個程序員寫好自己的函數聲明和定義,最后一個程序員頭文件整合在一起不就方便多了嗎?
其實這里把頭文件移除,add.h的頭文件也不包含了,強行運行程序也是可以的
但是會報警告,因為沒有聲明。這里還有另一種解決辦法。
因為函數來自外部文件,在(test_05_30_01.c)中聲明需要在前面加一個extern,extern是用來聲明外部符號的。
這樣就不會報警告了
這里還是推薦第一種,包含頭文件的方式,因為包含頭文件其實就相當于把add.h里的聲明拷貝過來,把#include"add.h"替換掉,本質上就相當于聲明。
還有另一種好處在下一篇文章去講。
價值10w的游戲引擎該怎么賣?
1.3 static和extern
static和extern都是C語言中的關鍵字
static是靜態的的意思,可以用來:
- 修飾局部變量
- 修飾全局變量
- 修飾函數
extern是用來聲明外部符號的,外部符號可以是全局變量,函數等
談起static和extern之前再講一下:作用域和生命周期
**作用域(scope)**是程序設計概念,通常來說,一段程序代碼中所用到的名字并不總是有效的,而限定這個名字的可用性的代碼范圍就是這個名字的作用域。
一句話來概括,這個名字在哪里可以使用,哪里就是作用域
-
局部變量的作用域就是變量坐在的局部范圍
可以看到這里的n就是局部變量,它的范圍就是第二個{ }里面,這個{ }外的printf運行的時候就會發生報錯。 -
全局變量的作用域就是整個工程(項目)
甚至在函數內,其他.c文件內也可以作用,附以代碼截圖
不過全局變量在其他.c文件里想要使用,需要聲明外部符號extern,告訴編譯器這個n來自外部,是其他源文件的,所以全局變量無論是在哪里定義的,整個工程想使用都是可以的。
生命周期指的是變量的創建(申請內存)到變量的銷毀(收回內存)之間的一個時間段。
- 局部變量的生命周期是:進入作用域變量創建,生命周期開始,出作用域生命周期結束
- 全局變量的聲明周期是:整個程序的生命周期(即main函數的生命周期,從main函數開始到return 0)
1.3.1 static修飾局部變量
正常情況下,這個程序輸出的結果就是5個2
test函數中的局部變量n是每次進入test函數先創建變量(生命周期開始)并賦值為0,然后++,再打印,出函數的時候變量生命周期將要結束(釋放內存)
但加入static修飾局部變量n之后,就輸出2,3,4,5,6
稍作反推,我們就能推導出這里n具有了累加的效果,其實是test函數中的n創建好之后,出函數的時候是不會銷毀的,重新進入函數也就不會重新創建變量。
每次用的是上一次留下來的值,相當于static int n = 1;是個擺設,追究底層原理也可以進入調試轉到反匯編看一下
C語言代碼全轉換成匯編語句時,沒一串代碼轉換出的匯編指令數量不定,但是按f11進入函數之后,static int n = 1;無匯編指令,而且繼續按f11調試的時候,會跳過這條語句。
由此我們可以得出結論:static修飾局部變量改變了變量的生命周期,生命周期改變的本質是改變了變量的存儲類型
這是代碼在內存中的存儲,本來一個局部變量時存儲在內存的棧區的,但是被static修飾后存儲到了靜態區。存儲在靜態區的變量和全局變量是一樣的,生命周期就和程序的生命周期一樣了,只有程序結束,變量才銷毀,內存才回收,但是作用域不變,即還是只能在局部變量使用。
1.3.2 static修飾全局變量
這串代碼再熟悉不過了,extern是用來聲明外部符號的,如果一個全局變量的符號在A文件中定義的,在B文件中想使用,就可以使用extern進行聲明,然后使用
但是如果我們在test2.c里的全局變量n前加static后
現象原因:
一個全局變量被static修飾,使得這個全局變量只能在本源文件內使用,不能在其他源文件內使用
現象解釋:
本質原因是全局變量默認是具有外部鏈接屬性的,在外部的文件中想要使用,只要是黨的聲明就可以使用。但是全局變量被static修飾之后,外部連接屬性就變成了內部連接屬性,只能在自己所在的源文件內部使用了,其他源文件,即使聲明了,也是無法正常使用的。
1.3.3 static修飾函數
這里和siatic修飾全局變量是類似的
正常情況下是可以運行的
但加入static之后修飾函數之后
一個函數在整個工程都可以使用,但被static修飾后,只能在本文件內部使用,其他文件無法正常的鏈接使用了
本質是因為函數默認是具有外部鏈接屬性,使得函數在整個工程中只要適當聲明就可以被使用,但是被static修飾后變成了內部鏈接屬性,使得函數只能在自己所在的源文件內部使用。
總結:當一個全局變量或函數只想在源文件內部使用,不想被其他源文件使用,就可以使用static修飾。
總結
例如:以上就是今天要講的內容,本文算是數組的徹底結束了,下一篇文章主播開始寫掃雷,主播寫這篇文章最后也是燃盡了,喜歡的兄弟們不要忘了一鍵三連給予支持。