原文鏈接:https://my.oschina.net/kmodel/blog/619368
在上一講中,簡單介紹了函數(shù)的定義和使用,只要你想完成一個新功能,首先想到的應該是定義一個新的函數(shù)來完成這個功能。這講繼續(xù)介紹函數(shù)的其他用法和注意事項。 一、函數(shù)的聲明1.在C語言中,函數(shù)的定義順序是有講究的:默認情況下,只有后面定義的函數(shù)才可以調(diào)用前面定義過的函數(shù)
第5行定義的main函數(shù)調(diào)用了第1行的sum函數(shù),這是合法的。如果調(diào)換sum函數(shù)和main函數(shù)的順序,在標準的C編譯器環(huán)境下是不合法的(不過在GCC編譯器環(huán)境下只是一個警告) ? 2.如果想把函數(shù)的定義寫在main函數(shù)后面,而且main函數(shù)能正常調(diào)用這些函數(shù),那就必須在main函數(shù)的前面進行函數(shù)的聲明
在第11行定義了sum函數(shù),在第2行對sum函數(shù)進行了聲明,然后在第6行(main函數(shù)中)就可以正常調(diào)用sum函數(shù)了。 ? 3.函數(shù)的聲明格式1> 格式
只要你在main函數(shù)前面聲明過一個函數(shù),main函數(shù)就知道這個函數(shù)的存在,就可以調(diào)用這個函數(shù)。而且只要知道函數(shù)名、函數(shù)的返回值、函數(shù)接收多少個參數(shù)、每個參數(shù)是什么類型的,就能夠調(diào)用這個函數(shù)了,因此,聲明函數(shù)的時候可以省略參數(shù)名稱。比如上面的sum函數(shù)聲明可以寫成這樣:
究竟這個函數(shù)是做什么用的,還要看函數(shù)的定義。 ? 2> 如果只有函數(shù)的聲明,而沒有函數(shù)的定義,那么程序?qū)阪溄訒r出錯 下面的寫法是錯誤的:
? 二、多源文件開發(fā)1.為什么要有多個源文件1> 在編寫第一個C程序的時候已經(jīng)提到:我們編寫的所有C語言代碼都保存在拓展名為.c的源文件中,編寫完畢后就進行編譯、鏈接,最后運行程序。 2> 在前面的學習過程中,由于代碼比較少,因此所有的代碼都保存在一個.c源文件中。但是,在實際開發(fā)過程中,項目做大了,源代碼肯定非常多,很容易就上萬行代碼了,甚至上十萬、百萬都有可能。這個時候如果把所有的代碼都寫到一個.c源文件中,那么這個文件將會非常龐大,也非常惡心,你可以想象一下,一個文件有十幾萬行文字,不要說調(diào)試程序了,連閱讀代碼都非常困難。 3> 而且,公司里面都是以團隊開發(fā)為主,如果多個開發(fā)人員同時修改一個源文件,那就會帶來很多麻煩的問題,比如張三修改的代碼很有可能會抹掉李四之前添加的代碼。 4> 因此,為了模塊化開發(fā),一般會將不同的功能寫到不同的.c源文件中,這樣的話,每個開發(fā)人員都負責修改不同的源文件,達到分工合作的目的,能夠大大提高開發(fā)效率。也就是說,一個正常的C語言項目是由多個.c源文件構成。 ? 2.將sum函數(shù)寫到其他源文件中接下來就演示一下多個源文件的開發(fā),我將前面定義的sum函數(shù)寫在另一個源文件(命名為sum.c)中。這時候就有兩個源文件: 1> main.c文件
2> sum.c文件
? 3.在main函數(shù)中調(diào)用sum函數(shù)1> 現(xiàn)在想在main函數(shù)中調(diào)用sum函數(shù),那么你可能會直接這樣寫:
這種寫法在標準C語言編譯器中是直接報錯的,因為main函數(shù)都不知道sum函數(shù)的存在,怎么可以調(diào)用它呢?。?! 2> 我們應該騙一下main函數(shù),sum函數(shù)是存在的,告訴它sum函數(shù)的返回值和參數(shù)類型即可。也就是說,應該在main函數(shù)前面,對sum函數(shù)進行聲明。 main.c文件應該寫成下面這樣
注意第3行,加了一個sum函數(shù)的聲明。為了檢驗sum函數(shù)的調(diào)用結果,在第9行用prinf函數(shù)將結果輸出。 ? 4.編譯所有的源文件sum.c和main.c都編寫完畢后,就可以使用gcc指令進行編譯了。同時編譯兩個文件的指令是:cc -c main.c sum.c 編譯成功后,生成了2個.o目標文件 也可以單獨編譯: cc -c main.c cc -c sum.c ? 5.鏈接所有的目標文件前面已經(jīng)編譯成功,生成了main.o和sum.o文件?,F(xiàn)在應該把這2個.o文件進行鏈接,生成可執(zhí)行文件。 1> 注意,一定要同時鏈接兩個文件。如果你只是單獨鏈接main.o或者sum.o都是不可能鏈接成功的。原因如下:
可以看出,main.o和sum.o有密不可分的關系,其實鏈接的目的就是將所有相關聯(lián)的目標文件和C語言函數(shù)庫組合在一起,生成可執(zhí)行文件。 2> 鏈接main.o和sum.o文件:cc main.o sum.o,生成了可執(zhí)行文件a.out 3> 運行a.out文件:./a.out,運行結果是在屏幕上輸出了:
說明函數(shù)調(diào)用成功,我們已經(jīng)成功在main.c文件的main函數(shù)中調(diào)用了sum.c文件中的sum函數(shù) 4> 從中也可以得出一個結論:只要知道某個函數(shù)的聲明,就可以調(diào)用這個函數(shù),編譯就能成功。不過想要這個程序能夠運行成功,必須保證在鏈接的時候能找到函數(shù)的定義。 ? 三、#include理解完前面的知識后,接下來就可以搞懂一個很久以前的問題:每次寫在最前面的#include是干啥用的? 1.#include的作用先來看一個最簡單的C程序:
這個程序的作用是在屏幕上輸出Hello,World!這一串內(nèi)容,我們主要關注第一行代碼。
也就是說你完全可以將第3行~第7行的代碼放到其他文件中,然后用 #include 指令包含進來,比如: 1> 將第3行~第7行的代碼放到my.txt中 2> 在main.c源文件中包含my.txt文件
? 2.#include可以使用絕對路徑上面的#include "my.txt"使用的是相對路徑,其實也可以使用絕對路徑。比如#include "/Users/apple/Desktop/my.txt" ? 3.#include <>和#include ""的區(qū)別二者的區(qū)別在于:當被include的文件路徑不是絕對路徑的時候,有不同的搜索順序。 1> 對于使用雙引號""來include文件,搜索的時候按以下順序:
2> 對于使用尖括號<>來include文件,搜索的時候按以下順序:
我這里使用的是clang編譯器,clang設置include路徑是(4.2是編譯器版本):/usr/lib/clang/4.2/include Mac系統(tǒng)的include路徑有:
? 4.stdio.h我們已經(jīng)知道#include指令的作用了,可是為什么要在第一行代碼包含stdio.h呢?
? 5.頭文件.h和源文件.c的分工跟printf函數(shù)一樣,我們在開發(fā)中會經(jīng)常將函數(shù)的聲明和定義寫在不同的文件中,函數(shù)聲明放在.h頭文件中,函數(shù)定義放在.c源文件中。 下面我們將sum函數(shù)的聲明和定義分別放在sum.h和sum.c中
然后在main.c中包含sum.h即可使用sum函數(shù) 其實sum.h和sum.c的文件名不一樣要相同,可以隨便寫,只要文件名是合法的。但還是建議寫成一樣,因為一看文件名就知道sum.h和sum.c是有聯(lián)系的。 運行步驟分析: 1> 在編譯之前,預編譯器會將sum.h文件中的內(nèi)容拷貝到main.c中 2> 接著編譯main.c和sum.c兩個源文件,生成目標文件main.o和sum.o,這2個文件是不能被單獨執(zhí)行的,原因很簡單: * sum.o中不存在main函數(shù),肯定不可以被執(zhí)行 * main.o中雖然有main函數(shù),但是它在main函數(shù)中調(diào)用了一個sum函數(shù),而sum函數(shù)的定義卻存在于sum.o中,因此main.o依賴于sum.o 3> 把main.o、sum.o鏈接在一起,生成可執(zhí)行文件 4> 運行程序 ? 說到這里,有人可能有疑惑:可不可以在main.c中包含sum.c文件,不要sum.h文件了?大家都知道#include的功能是拷貝內(nèi)容,因此上面的代碼等效于: 這么一看,語法上是絕對沒有問題的,main.c、sum.c都能編譯成功,分別生成sum.o、main.o文件。但是當我們同時鏈接main.o和sum.o時會出錯。原因:當鏈接這兩個文件時鏈接器會發(fā)現(xiàn)sum.o和main.o里面都有sum函數(shù)的定義,于是報"標識符重復"的錯誤,也就是說sum函數(shù)被重復定義了。默認情況下,C語言不允許兩個函數(shù)的名字相同。因此,不要嘗試去#include那些.c源文件。 ? 有人可能覺得分出sum.h和sum.c文件的這種做法好傻B,好端端多出2個文件,你把所有的東西都寫到main.c不就可以了么?
轉(zhuǎn)載于:https://my.oschina.net/kmodel/blog/619368 來源:https://www./content-4-443101.html |
|