關於函式原型的對話

2021-09-08 21:29:05 字數 2768 閱讀 1969

#include

int main()

void print_star()

void print_message()

執行結果:

******************

how do you do!

******************

————譚浩強 ,《c程式設計》(第四版),清華大學出版社,2023年6月,p171

甲:這麼短的一段**,會有什麼問題嗎?

乙:所謂「山不在高」,**有沒有問題也不在於長短。這段**確實有問題,而且問題還不少。

甲:我怎麼沒看出來,好像除了在「

這樣就足夠了,簡單又純粹,根本就沒必要自己再定義函式。自己定義函式屬於出力不討好的行為。

甲:倒也是,現在看來確實沒有必要。如果不考慮這一點的話,**還存在哪些問題呢?

乙:函式原型——也就是有時候所說的函式宣告,寫的有些不倫不類之感。

甲:怎麼不倫不類了呢?

乙:void print_star();和void print_message();這兩個函式原型的()內應該寫void,

void print_star(void);

void print_message(void);

裡面什麼也不寫,通常是訂立c標準之前老式c語言函式宣告的寫法。

甲:感覺按照老式寫法也有好處啊,至少少寫了幾個字母。

乙:如果按照老式的寫法,這種用不到函式返回值的函式的宣告根本就沒必要寫。

甲:那編譯器不是把這兩個函式當作返回值為int型別的函式了嗎?

乙:是的。但c標準之前根本就沒有void這個關鍵字,因此只要不使用這兩個函式的返回值它們的返回值是int型別也無所謂。

甲:哦,就是說void print_star();前面的void是標準後的新風格,而後面()裡什麼都不寫是標準前的舊風格。所以有點不倫不類,是嗎?

乙:正是這樣。有點戴假辮子穿西裝的假洋鬼子氣派。

甲:但按照新式風格寫似乎不很簡潔啊?

乙:這會有相應的補償。函式原型的意義在於希望編譯器幫助檢查函式呼叫時引數型別、個數及函式返回值型別方面是否存在錯誤。比如,如果一旦函式呼叫誤寫成了

print_star(5,6);

這種錯誤的寫法,當函式原型的()裡面寫了void時,這個錯誤立刻就能檢查出來。

而當函式宣告的()裡面什麼都不寫的情況下,這個錯誤就檢查不出來。所以void print_star();這種半舊半新的寫法,即沒有獲得舊風格的好處(可以完全不寫函式宣告),也沒有獲得新風格的好處。相當於寫了乙個毫無意義毫無益處的函式原型。寫乙個毫無意義的函式原型難道不是很滑稽麼?這情形就和在**中多定義幾個毫無用處的變數是一樣的。

甲:嗯,多定義幾個沒有用的變數確實顯得有點傻。但如果我執意按照舊風格寫——索性不寫那種函式說明或者不在()內寫任何東西,因為我覺得這樣可以少打幾個字,標準不也同樣容許嗎?這樣行不行呢?

乙:首先,c標準(c89)加入函式原型這個概念自有其道理,執意守舊從長遠和大局的角度來看因小失大、得不償失。即使是c語言的發明人也強烈建議使用函式原型這種新的程式設計方式。其次,c標準之所以還容許舊的風格是因為已經有了無數的舊風格的c**在執行,容許絕對不代表提倡。淘汰舊有的落後的東西有時需要一段時間。c99在這方面的要求就更加嚴格了。比如在c89中你可以寫

int print_star();

或者乾脆不寫這個函式宣告。不寫的原因是c89把沒宣告過的函式都當作返回值為int型別的函式,亦即int在很多情況下可以省略。但c99就不容許省略int,所以在執行c99標準的編譯器上不寫函式原型的可能性就不存在了。

從這裡可以看得出c語言的進化趨勢,清清楚楚地寫出函式原型才是先進生產力的代表。

甲:那就是說前面的**應該這樣寫嗎?

#include int main()

void print_star()

void print_message()

乙:main()、print_message和print_star()的函式定義的()內也應該寫void。所謂清清楚楚意味著應該盡量不要使用潛規則。

甲:哦。還有別的嗎?

乙:還有這個**中函式原型的位置也值得說說。在這段**中,兩個函式原型都寫在了main()函式之內,這是違背常理的。

甲:何以見得呢?

乙:因為定義函式的目的就是為了讓其他函式使用。樣本**中把函式宣告寫在了main()之內,根據作用域準則,這就意味著這些函式僅僅在main()中得到了說明,在其他函式中由於沒有得到說明而不能呼叫直接呼叫。這種作繭自縛式的自我限制顯然與定義函式的本意是背道而馳的,是在自己捆自己的手腳。這是典型的程式結構劣化。

這種寫法非常猥瑣,一方面把main()函式內搞得凌亂不堪,另一方面還限制妨礙了其他函式直接呼叫這兩個函式——除非你在其他函式中再寫一次函式宣告。

甲:那應該寫在何處呢?

乙:常規的寫法是寫在所有函式定義之前。

#include void print_star(void);

void print_message(void);

int main(void)

void print_star(void)

void print_message(void)

這樣的話在各個函式體中都可以隨時呼叫這兩函式。在適當的時候還便於把這些函式原型組織到*.**件中。

甲:*.h中的h據說是head的意思,就是因為這些東西通常寫在原始檔的前面的緣故嗎?

乙:可能吧。

js關於原型建構函式和原型鏈的理解

js的物件導向方式的函式有很多種方式,其中有兩個比較重要的是兩種方式一是建構函式模式,一是原型模式。1 建構函式模式如 function persion name,age var person1 new person alex 29 person1.sayname alex var person2 ...

關於建構函式和原型的實驗筆記

關於建構函式,我想到乙個比方。b 本是b生的,但是b斷絕了和他的母子關係,a無子女,決定領養b,於是a就成了b的繼母,也就是b法律上的媽媽。你問b的媽媽叫什麼,就相當於問b的建構函式是誰。這種關係很容易改變,立個什麼字據或證明就可以了。而原型就相當於是b身上的基因,這是領養這種關係改變不了的,屬於先...

關於c 中函式原型宣告的小討論

或許我們都知道在寫程式時如果把被調函式寫到了main 函式的後面,那麼我們就必須在main 函式的前面對被調函式的原型進行宣告。但是你知道這其中的原理嗎?先來看個程式 include using namespace std int main int a 1,b 2 int s s add a,b c...