在C語言中,程序從main()函數開始,其他函數只有被main函數調用才能運行。
當編譯好的可執行程序從shell解釋器運行時,主函數將被shell啟動並開始運行。
C語言的函數在使用時要經歷三個步驟:聲明、定義和調用。
函數聲明就是給出函數的原型,讓程序員知道如何給函數傳遞參數,如何接收返回值,讓編譯器知道如何檢查代碼類型。主函數的聲明如下:
int main();
它的返回值是int類型,不需要參數。
printf()函數的聲明如下:int printf(const char* fmt,...);
它的返回值是int類型,第壹個參數是格式字符串,然後後面可以跟變量參數。
函數聲明的語法是:
返回值類型的函數名(參數類型0,參數變量0,參數類型1,參數變量1);
如果有多個參數,請用逗號分隔。每個參數都有壹個類型和壹個變量名,聲明時可以省略參數的變量名。最後,用分號結束聲明語句。
如果不想讓人看到函數的源代碼,可以只提供壹個語句和編譯後的文件,別人只能看到匯編代碼(笑)。C語言的這種設計有利於知識產權的保護。
函數定義是指函數體在聲明後用不帶分號的大括號表示,函數的具體代碼寫在大括號裏面。
上圖中的main()函數是定義,printf()函數是聲明。
定義,它實現了函數的內容。函數不能多次定義,否則編譯器不知道使用哪個定義的代碼。
但是函數可以多次聲明,只要聲明是相同的並且不矛盾。
只要放上兩個大括號{},就定義了壹個函數。空實現也是壹種實現。可以先占這個位置,以後再填具體的功能碼。也就是先給出整個方案的框架,然後再填充細節。
函數實現後,必須調用它才能運行。
除了main函數由shell啟動之外,其他所有函數都應該由main函數直接或間接調用。
當壹個函數運行時,實際上有壹個從主函數到它的調用鏈。
函數調用的語法是:
函數名(自變量變量0,自變量變量1);
如果有多個參數,請用逗號分隔。如果希望接收函數調用的返回值,可以使用變量來接收:
返回值變量=函數名(自變量變量0,自變量變量1);
返回值變量的類型要和函數的返回值類型壹致,使用前要聲明。
對於有返回值的函數,沒有必要接收它的返回值。例如,盡管printf()有壹個int類型的返回值來指示打印了多少個字符,但它通常不會被接收。
所以C語言的入口代碼是printf(“hello world \ n”);
而不是int ret = printf(" hello world \ n ");
函數名在C語言中屬於標識。
標識符的命名規則是以下劃線或大小寫字母開頭,然後可以是數字、字母、下劃線(但不能是運算符或其他特殊符號)。
它們在代碼中用於表示變量名、結構類型名、函數名或用於goto的標簽。
基本類型的類型名被定義為關鍵字,不能再用作標識符。
結構
int a;
int b;
} s;
是壹個標識符,指示結構類型。
a是標識符,表示結構的成員變量a。
S是壹個標識符,代表變量S,它的類型是結構類型S。
函數名也是標識符,所以函數名也要以下劃線或大小寫字母開頭,不能是關鍵字、運算符或其他特殊符號。
0123,這不可能是函數名,C語言中以0開頭的數是八進制數。
0x123,也不能是函數名,以0x開頭的數是十六進制的數16。
Main,可以作為函數名,是主函數。整個程序中只能有壹個,不能作為普通函數的名字。
__schedule以下劃線開頭,可以用作函數名。
但是,以兩個下劃線開頭的函數大多是Linux系統或C庫的函數。普通函數最好不要這樣命名。
Char,這不能是函數名,是字符型的關鍵字。
+,也做不到,是加法的運算符。
CreateWindowEx,可以作為函數名,看起來是典型的匈牙利風格,微軟代碼(笑)。這個函數是壹個在windows系統上創建窗口的API。
匈牙利風格的代碼是微軟的壹種流行風格。函數名以壹個或多個英文單詞命名,每個單詞的首字母大寫,其他字母小寫。
但是Linux代碼(包括第三方軟件)仍然保持了古代C代碼的下劃線風格,字母全部小寫,單詞用下劃線隔開,使用的縮寫更多。
有時縮寫後面只剩下幾個字母,直接組成壹個新詞作為函數名。
例如,在Linux上啟動壹個新程序的函數executable()是壹個縮寫詞。
要執行的英文單詞叫execute,windows上的可執行程序叫exe文件,就是這個單詞的前三個字母,Linux也選擇了這三個字母。
三個字母cve來自主函數的完整參數列表:
int main(int argc,char* argv[],char * envp);
main函數的完整聲明是這樣的,int main()是簡化版。
第壹個參數argc表示傳遞給main函數的參數數量。作為命令行參數傳遞。Arg是參數argument的縮寫,c是count,是參數的個數。
Argv是參數字符串數組(傳遞給main函數),v指vector。
Envp是環境變量環境路徑的路徑。
因此,啟動main的系統調用稱為executable(),而不是StartProgram()。
後者雖然明顯好理解,但是字母多,系統調用的API也不是壹眼就能看出來啟動進程的(汗)。
回到開頭,main()函數是由Linux上的executable () API啟動的,然後由main函數直接或間接調用其他函數。
未被main函數調用(直接或間接)的函數將不會運行。
上面顯示的代碼將只打印add,因為main只調用add()函數,而不調用sub()函數。
這個簡單的代碼,只有這三個函數,sub()沒有被調用過。