#include <stdio.h>
int main(void)
{
printf("That is Right Style\n");
return 0;
}
在一個(gè)標(biāo)準(zhǔn)的C語言程序中,最特殊的莫過于main函數(shù)了,而說到底它就是一個(gè)函數(shù)而已,僅僅因?yàn)樗匚惶厥鈸碛械谝粓?zhí)行權(quán)力,換句話說,難道因?yàn)橐粋€(gè)人是省長它就不是人類了?所以函數(shù)該有的它都應(yīng)該有,那么函數(shù)還有什么呢?
函數(shù)大體上分為內(nèi)聯(lián)函數(shù)(C99)(內(nèi)聯(lián)函數(shù)并非C++專屬,C語言亦有,具體見前方鏈接)和非內(nèi)聯(lián)的普通函數(shù),它們之間有一個(gè)很明顯的特點(diǎn)(一般情況下),那就是不寫原型直接在main函數(shù)上方定義,即使不加'inline'關(guān)鍵字,也能被編譯器默認(rèn)為內(nèi)聯(lián)函數(shù),但之后帶來的某些并發(fā)問題就不是編譯器考慮的了。
普通函數(shù)正確的形式應(yīng)該為聲明與定義分離,聲明就是一個(gè)函數(shù)原型,函數(shù)原型應(yīng)該有一個(gè)函數(shù)名字,一個(gè)參數(shù)列表,一個(gè)返回值類型和一個(gè)分號(hào)。定義就是函數(shù)的內(nèi)在,花括號(hào)內(nèi)的就是函數(shù)的定義:
//...
int function(int arg_1, float arg_2);
//...
int main(int argc, char* argv[])
{
int output = function(11, 22.0);
printf("%d\n",output);
return 0;
}
int function(int arg_1, float arg_2)
{
int return_value = arg_1;
float temp_float = arg_2;
return return_value;
}
依上所述,當(dāng)非必要時(shí),在自己編寫函數(shù)的時(shí)候請注意在開頭(main函數(shù)之前)寫上你的函數(shù)的原型,并且在末尾(main函數(shù)之后)寫上你的函數(shù)定義,這是一個(gè)很好的習(xí)慣以及規(guī)范。所謂代碼整潔之道,就是如此。
函數(shù)的另一種分類是,有返回值和無返回值,返回值的類型可以是內(nèi)建(build-in)的也可以是自己定義的(struct, union之類),無返回值則是void。
void main()這種寫法?因?yàn)檫@完全是中國式教育延伸出來的譚式寫法,main函數(shù)的返回值看似無用,實(shí)際上是由操作系統(tǒng)接收,在Windows操作系統(tǒng)下也許無甚"大礙"(實(shí)際上有),當(dāng)你使用Linux的過程中你會(huì)清晰的發(fā)現(xiàn)一個(gè)C語言程序的main返回值關(guān)系到一個(gè)系統(tǒng)是否能正常,高效的運(yùn)行,這里稍微提一句,0在Linux程序管道通信間代表著無錯(cuò)可行的意思。所以請扔掉void main這種寫法。為什么我們對 main()這種省略返回值的寫法置有微詞?能發(fā)明這種寫法的人,必定是了解了,在C語言中,如果一個(gè)函數(shù)不顯式聲明自己的返回值,那么會(huì)被缺省認(rèn)為是int,但這一步是由編譯器掌控,然而C語言設(shè)計(jì)之初便是讓我們對一切盡可能的掌握,而一切不確定因子我們都不應(yīng)該讓它存在。其次有一個(gè)原則,能自己做的就不要讓編譯器做。
為什么我們對參數(shù)放空置有不滿(int main())?在C語言中,一個(gè)函數(shù)的參數(shù)列表有三種合法形態(tài):
int function();
int function(void);
int function(int arg_n);
int function(int arg_n, ...);
第一種代表擁有未知個(gè)參數(shù),第二種代表沒有參數(shù),第三種代表有一個(gè)參數(shù),第四種代表擁有未知個(gè)參數(shù),并且第一個(gè)參數(shù)類型為int,未知參數(shù)在C語言中有一個(gè)解決方案就是,可變長的參數(shù)列表,具體參考C標(biāo)準(zhǔn)庫,在此我們解釋的依據(jù)就是,我們要將一切都掌控在自己的手中,我們不在括號(hào)內(nèi)填寫參數(shù),代表著我們認(rèn)為一開始的意思是它為空,正因此我們就應(yīng)該明確說明它為void,而不該讓它成為一個(gè)未知參數(shù)長度的函數(shù),如此在你不小心傳入?yún)?shù)的時(shí)候,編譯器也無法發(fā)現(xiàn)錯(cuò)誤。
int main(int argc, char* argv[]) 和 int main(void)才是我們該寫的C語言標(biāo)準(zhǔn)形式
對于縮進(jìn),除了編譯器提供的符號(hào)縮進(jìn)之外,我們可以自己給自己一個(gè)規(guī)范(請少用或者不用Tab),比如每一塊代碼相教上一個(gè)代碼塊有4格的縮進(jìn)。
對于學(xué)習(xí)C語言,請使用.c文件以及C語言編譯器練習(xí)以及編寫C程序,請不要再使用C++的文件編寫C語言程序,并且自圓其說為了效率而使用C++的特性在C語言中,我們是祖國的下一代,是祖國的未來,請不要讓自己毀在當(dāng)下,珍愛編程,遠(yuǎn)離清華大學(xué)出版社
之所以如此敘述,并不是因?yàn)榍榫w,而是當(dāng)真如此,下方代碼:
/*file: test.c*/
#include <stdio.h>
#define SIZES 5
int main(void)
{
int* c_pointer = malloc(SIZES * sizeof(int));
/*發(fā)生了一些事情*/
free(c_pointer);
return 0;
}
這是一段標(biāo)準(zhǔn)的C語言程序,但是它能在C++個(gè)編譯器下編譯運(yùn)行嗎?換句話說當(dāng)你將文件擴(kuò)展名由.c改為.cpp之后,它能編譯通過嗎?答案是不能。
為什么?答案是C++并不支持void*隱式轉(zhuǎn)換為其他類型的指針,但是C語言允許。還有許許多多C于C++不相同的地方,興許有人說C++是C的超集,但我并不這么認(rèn)為,一門語言的出現(xiàn)便有它的意義所在,關(guān)鍵在于我們?nèi)绾伟l(fā)揮它的最大優(yōu)勢,而不是通過混淆概念來增強(qiáng)實(shí)用性
程序式子的寫法
一個(gè)人活在世界上,時(shí)時(shí)刻刻都注意著自己的言行舉止,而寫程序也是如此,對于一個(gè)規(guī)范的能讓別人讀懂的程序而言,我們應(yīng)該盡可能減少阻礙因子,例如:
int main(void)
{int complex_int=100;
int i,j,k,x;
for(int temp=0;temp<complex_int;++temp){k=temp;
x=k+complex_int;}
printf(complex_int="%d is k=%d x=%d\n",complex_int,k,x);
return 0;}
對于上述的代碼,我總是在班級里的同學(xué)手下出現(xiàn),但這段代碼除了讓別人困惑以外,自己在調(diào)試的時(shí)候也是十分不方便,每每遇到問題了,即便IDE提示了在某處錯(cuò)誤,你也找不到問題所在,經(jīng)常有人來問我哪里錯(cuò)了,大部分情況都是少了分號(hào),括號(hào),或者作用域超過,原因在哪?
要是一開始將代碼寫清楚了,這種情況簡直是鳳毛麟角,想遇上都難。對于一個(gè)代碼而言,我們應(yīng)該注意讓其變得清晰。
等號(hào)兩邊使用空格:
int complex_int = 100;
使用多個(gè)變量的聲明定義,或者函數(shù)聲明定義,函數(shù)使用時(shí),注意用空格分開變量:
int i, j, k, x;//但是十分不建議這么聲明難以理解意義的變量
printf("complex_int = %d is k = %d x = %d\n", complex_int, k, x);
void present(int arg_1, double arg_2);
對于一個(gè)清晰的程序而言,我們要讓每一個(gè)步驟清晰且有意義,這就要求我們在編寫程序的時(shí)候盡量能讓代碼看起來結(jié)構(gòu)化,或者整體化。盡量讓每個(gè)程序式子為一行,如果有特別的需要讓多個(gè)式子寫在同一行,可以使用,操作符進(jìn)行組合,但是會(huì)讓程序更難理解,日后調(diào)試的時(shí)候也更難發(fā)現(xiàn)錯(cuò)誤。
/*Style 1*/
for(int temp = 0;temp < complex_int;++temp)
{
k = temp;
x = k + complex_int;
}
/*Style 2*/
for(int temp = 0;temp < complex_int;++temp){
k = temp;
x = k + complex_int;
}
對于上方的代碼,是C語言代碼花括號(hào)的兩種風(fēng)格,最好能選擇其中一種作為自己的編程風(fēng)格,這樣能讓你的程序看起來更加清晰,混合使用的利弊并不好說,關(guān)鍵還是看個(gè)人風(fēng)格。
對于作用域而言,在C語言中有一個(gè)經(jīng)常被使用的特例,當(dāng)一個(gè)條件語句,或者循環(huán)只有一條語句的時(shí)候,我們常常省略了花括號(hào){},而是僅僅使用一個(gè)分號(hào)作為結(jié)尾,這在很多情況下讓代碼不再啰嗦:
if(pointo_int == NULL)
fprintf(stderr, "The pointer is NULL!\n");
else
{
printf("%d\n",*pointo_int);
pointo_int = pointo_int->next;
}
在這段代碼中if語句下方的代碼并沒有使用{}運(yùn)算符進(jìn)行指明,但是根據(jù)語法,該語句的確是屬于if語句的作用范圍內(nèi),如果我們此時(shí)寫上了{}反而會(huì)令代碼看起來過于啰嗦。但是有的時(shí)候,這條特性并不是那么的有趣,當(dāng)使用嵌套功能的時(shí)候,還是建議使用{}進(jìn)行顯式的范圍規(guī)定,而不是使用默認(rèn)的作用域:
for(int i = 0;i< 10;++i)
for(int k = 0;k < 10;++k)
while(flag != 1)
set_value(arr[i][k]);
這段代碼,看起來十分簡潔,但是確實(shí)是一個(gè)很大的隱患,當(dāng)我們要調(diào)試這段代碼的時(shí)候,總是需要修改它的構(gòu)造,而這就帶來了潛在的隱患。所以建議在使用嵌套的時(shí)候,無論什么情況,都能使用{}進(jìn)行包裝。
綜上所述,在開始編寫一個(gè)標(biāo)準(zhǔn)C語言程序的時(shí)候,請先把下面這些東西寫上:
#include <stdio.h>
int main(void)
{
return 0;
}
對于main的參數(shù),有興趣的可以查閱我的文章,或者自行谷歌,在此問題上百度也是可以的。