2010-10-29 89 views
5

我遵循指南來學習詛咒,並且原型中的所有C代碼在main()之前都會運行,然後再定義它們。在我的C++學習中,我聽說過函數原型,但從來沒有這樣做過,就我所知,它並沒有在代碼編譯方面做出太大的改變。這比程序員的個人選擇更重要嗎?如果是這樣,爲什麼它包含在C中呢?功能原型設計的要點是什麼?

+4

當兩個函數互相調用時,您需要前向聲明。 – kennytm 2010-10-29 19:52:38

+1

[C89,C90或C99中所有函數都需要原型嗎?](http://stackoverflow.com/questions/434763/are-prototypes-required-for-all-functions-in-c89-c90-或-c99) – 2010-10-29 19:56:23

+1

我不明白爲什麼。我不是問他們是否有必要,我只是不明白爲什麼他們首先在標準中。 – Maulrus 2010-10-29 19:58:20

回答

3

在C原型中,需要知道你的程序知道你有一個叫做x()的函數,當你還沒有定義它的時候,y()知道存在並且存在一個x()。 C自頂向下編譯,因此需要在手是簡短答案之前進行定義。

x(); 
y(); 
main(){ 

} 

y(){ 
x(); 
} 

x(){ 
... 
more code ... 
maybe even y(); 
} 
+1

我認爲這個答案完全忽略了這一點。首先,您可以在沒有原型的情況下調用任何函數,並且在定義之前(某些規則適用)。其次,「自上而下編譯」(不管是什麼意思)不是C的一部分,也沒有要求以某種特定方式編譯C的要求。 – Jens 2011-04-12 17:39:52

+0

第三,你的代碼縮減甚至不包含適當的原型!它是如此草率,'gcc -Wall -pedantic -std = c89 x.c'產生10個警告。 – Jens 2011-04-12 17:49:55

0

它可以讓你在其中說,你可以在一個單獨的.h文件,其中包括父容器類中定義的迭代器類的情況。既然你已經在迭代器中包含父頭,你不能有像「getIterator()」這樣的方法,因爲返回類型必須是迭代器類,因此它需要你在迭代器中包含迭代器頭父標題創建內含物的循環循環(一個包括另一個包括其本身,其中包括另一個,等等)。

如果你把迭代器類原型父容器內,可以有這樣的方法不包括迭代頭。它只是起作用,因爲你只是說這樣的對象存在並將被定義。

有避過它就像有一個預編譯的頭的方式,但在我看來,它是那麼優雅,並配有缺點的轉換。當然,這是C++,而不是C。然而,在實踐中,您可能會遇到這樣的情況,您希望以這種方式安排代碼,而不是將代碼放在一邊。

+0

C中的迭代器類?這個問題提到了C++,但是關於C的基本原理,所以我認爲需要一個不同的例子:-) – 2010-10-29 20:05:47

1

我的印象是,它是如此的客戶可以訪問圖書館.h文件,看看哪些功能是提供給他們,而不必瞭解實現(這將是在另一個文件)下。

用於查看函數返回的內容/參數。

+1

從頭文件中獲取可用的函數是一個壞主意,因爲頭文件可能包含應用程序員不可用的任意魔法。一位認真的開發人員將從隨庫提供的文檔中獲取所需的全部信息。對於標準C,POSIX以及更多(甚至Windows API),文檔可以免費使用,甚至可能已經存在(手冊頁,Windows幫助,...)如果您需要從頭文件中搜集原型,錯誤的軌道。 – Jens 2011-04-12 17:57:38

1

函數原型設計是編譯器編寫以前的一種遺留問題。過去,編譯器必須對源文件進行多次編譯才能編譯它,這被認爲是非常低效的。

在C中,在某些情況下,指的是在一個方式的功能是語法上等同於涉及變量:考慮一個指針指向一個功能與採用指針的變量。在編譯器的中間表示中,兩者在語義上是不同的,但從語法上來說,不能從上下文中確定標識符是變量,函數名稱還是無效標識符。

因爲它是從上下文無法確定,沒有函數原型,編譯器會需要讓你的上源的每個額外的一個階段,每次他們中的一個編譯文件。這會爲任何編譯添加額外的O(n)因子(即,如果編譯爲O(m),現在將爲O(m * n)),其中n是項目中文件的數量。在編譯時間已經達到幾個小時的大型項目中,使用雙通編譯器是非常不理想的。

轉發聲明所有的功能將允許編譯器來構建的功能表,因爲它掃描的文件,並能夠確定何時遇到的標識是否指函數或變量。由於這個原因,C(以及擴展C++)編譯器在編譯時可以非常高效。

+0

這不一定是真的 - 如果他們不需要函數原型,他們將不必重新解析相同的#包含三十多次。這就是爲什麼預編譯頭文件在減少MSVC編譯時間方面如此有效 - 因爲#including需要很長時間。 – Puppy 2010-10-29 21:04:11

+3

我喜歡這個開始。是的,彙編模型是怪罪。但我更喜歡這個模型的防守。建議C++編譯器在編譯時可以非常高效,最後是一場災難。來吧! – 2010-10-29 21:11:22

11

函數原型最初並不包含在C中。當你調用一個函數時,編譯器只是對你的單詞表示它會存在並採用你提供的參數類型。如果你得到參數順序,數字或類型錯誤,太糟糕了 - 你的代碼在運行時可能會以神祕的方式失敗。

爲了解決這些問題,更高版本的C添加了函數原型。在某些情況下,您的參數會隱式轉換爲聲明的類型,或者被標記爲與原型不兼容,編譯器可能會將錯誤的順序和類型數標記爲錯誤。這具有啓用可變參數函數和他們所需的特殊參數處理的副作用。

注意,在C(和不像在C++),函數聲明foo_t func()一樣聲明爲foo_t func(void)的函數。後者的原型沒有任何爭論。前者聲明一個沒有原型的函數。

+0

對於聲明和原型之間區別的最後一節+1。 – legends2k 2014-06-09 13:11:46