【云小課】基礎服務第42課 網絡知識一籮筐——揭開IP地址的神秘身份
1241
2025-03-31
首先C語言是一門面向過程的編程語言,它是由一系列的函數組成的。函數的使用必須遵守:
先聲明后使用的原則
舉個例子說明一下,下面是一個test.c的源程序:
#include
1
2
3
4
5
6
7
8
9
我們在terminal上用gcc編譯一下這個程序:
~$ gcc test.c -o test
1
然后就報了如下的錯誤:
test.c: In function ‘main’: test.c:4:2: warning: implicit declaration of function ‘sayHello’; did you mean ‘ftello’? [-Wimplicit-function-declaration] sayHello(); ^~~~~~~~ ftello test.c: At top level: test.c:7:6: warning: conflicting types for ‘sayHello’ void sayHello(){ ^~~~~~~~ test.c:4:2: note: previous implicit declaration of ‘sayHello’ was here sayHello(); ^~~~~~~~
1
2
3
4
5
6
7
8
9
10
11
12
正確的做法是在調用sayHello()函數前,先聲明這個函數。這里解釋一下,為什么在函數調用前需要先聲明,這主要是由編譯器的編譯過程決定的:
編譯器看到了一個不認識的函數調用:sayHello()函數。編譯器此時不會報錯,它認為在該源文件后面會找到這個函數的詳細信息,所以它記錄下這個函數,隨后會在文件中查找函數。
編譯器需要知道函數的返回類型,因此在它記錄下這個函數后,它會假設它返回int。
等到編譯器看到實際函數時,發現返回的不是int,而是void,所以它就會報出“conflicting types for ‘sayHello’的錯誤,就是說函數的返回類型沖突了。如果sayHello的返回值是int,它就不會報錯了,頂多給個警告。如果在調用前,就進行了函數聲明,那么編譯器在函數調用的地方就可以清楚地知道函數的返回類型,它就不用自己假設成int了,也就不會有后面的錯誤了,而這種假設通常很危險。這就是為什么在函數調用前必須先聲明的原因。
test.c的完整且正確的程序如下。
下面這種是在源文件開頭添加函數聲明:
#include
1
2
3
4
5
6
7
8
9
10
11
或是下面這種調整main函數與sayHello函數的位置:
#include
1
2
3
4
5
6
7
8
9
10
再次編譯運行,就完全沒有問題了:
~$ gcc test.c -o test ~$ ./test Tom says:Hello!
1
2
3
補充:運行目標程序時要加上./,為什么呢?因為在類Unix系統上,必須指定可執行文件所在的目錄,除非目錄已添加到PATH環境變量中。./表示當前目錄下。
其中調整函數的順序其實是一件很痛苦的事情,尤其在加入新入的函數的時候,特別容易出現上述錯誤。如果寫一些相互遞歸調用的函數,它們互相調用對方,那么總有一個函數在定義 前被調用了,那如何是好?有沒有一種方法既不用調整代碼,又能讓編譯器知道函數返回類型呢?有,將函數聲明都寫在源文件的開頭或用頭文件的形式將聲明與定義進行分離。我們來說說用頭文件的方式。
將函數聲明放在一個.h的頭文件中,然后再把.h文件包含進來就可以了。
函數聲明只是一個函數簽名,一條包含函數名、形參類型、返回類型的記錄。我們將上述函數的聲明放到一個叫tong.h的頭文件中去:
void sayHello();
1
在test.c引入tong.h頭文件
#include
1
2
3
4
5
6
7
8
9
10
這樣一來,編譯器在一開始就知道函數的返回類型,就不用稍后再找了,而且防止了編譯器假設函數的返回類型,可以顯式地告訴它了。這種告訴編譯器函數會返回什么類型的語句就叫函數聲明。如果代碼中有很多函數,而你又不想管它們在文件中的順序,那么可以在源文件開頭列出函數聲明,甚至可以把這些函數聲明放到一個頭文件中,再通過include指令包含進來。
小知識:
頭文件的名稱用雙引號括起來和用尖括號括起來的區別:
1.用雙引號括起來的文件名,編譯器就會在本地查找文件,如果是加上了目錄的文件名,編譯器就會在相對路徑下查找頭文件;
2.用尖括號括起來的文件名,編譯器就會在標準庫里找,gcc知道在哪里。在類Unix系統中,頭文件一般都放在/usr/local/include 、/usr/include這些地方。
以上談到的頭文件作用是為了能夠調整函數之間的順序,以下將介紹的頭文件作用是為了讓其他程序知道某個函數,從而達到共享這個函數的目的:
例如我們要共享如下這個加密函數,那么我們需要想辦法讓其他程序知道它,這時就可以用頭文件了:
void encrypt(char *message){ while(*message){ *message = *message ^ 31; message++; } }
1
2
3
4
5
6
1.創建一個encrypt.h的頭文件:
void encrypt(char *message);
1
2.在encrypt.c中包含這個頭文件,這樣可以讓其他程序知道encrypt()函數:
#include "encrypt.h" void encrypt(char *message){ while(*message){ *message = *message ^ 31; message++; } }
1
2
3
4
5
6
7
3.在test1.c程序中使用這個函數,只需要包含這個頭文件就可以了:
#include
1
2
3
4
5
6
7
8
9
這樣一來在主程序test1.c引入了encrypt.h,編譯器就可以知道encrypt()函數,這樣才能編譯代碼。最后,為了把所有東西編譯到一起,只需要把源文件都傳給gcc:
~$ gcc test1.c encrypt.c -o testEncrypt ~$ ./testEncrypt wzssp?hpms{
1
2
3
這樣把加密程序放到了一個單獨文件中,就可以在任何程序中使用它了。
至此.h頭文件的第二個作用也講完了,謝謝大家的支持。
C 語言
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。