函式原型
函式宣告在函式定義之前,並且會指定函式的名稱、傳回型別、儲存類別和其他屬性。 函式宣告也必須建立函式引數的類型和識別項,才能成為原型。
語法
declaration
:
declaration-specifiers
attribute-seq
opt init-declarator-list
opt ;
/* attribute-seq
opt 為 Microsoft 特定 */
declaration-specifiers
:
storage-class-specifier
declaration-specifiers
opt
type-specifier
declaration-specifiers
opt
type-qualifier
declaration-specifiers
opt
init-declarator-list
:
init-declarator
init-declarator-list
,
init-declarator
init-declarator
:
declarator
declarator
=
initializer
declarator
:
pointer
opt direct-declarator
direct-declarator
:: /* 函式宣告子 */
direct-declarator
(
parameter-type-list
)
/* 新樣式宣告子 */
direct-declarator
(
identifier-list
opt )
/* 舊樣式宣告子 */
原型的形式與函式定義的相同,但右括號後面加上分號即可終止原型,因此沒有主體。 在任何情況下,傳回類型必須與在函式定義中指定的傳回類型一致。
函式原型有下列重要用途:
它們會建立傳回
int
以外之類型的函式的傳回類型。 雖然傳回int
值的函式不需要原型,仍建議使用原型。如果沒有完整的原型,就會執行標準轉換,但不會嘗試根據參數數目檢查引數的類型或數目。
原型用於在定義這些函式之前初始化函式指標。
參數清單用於檢查函式呼叫中的引數是否與函式定義中的參數相符。
每個參數的轉換類型決定函式呼叫置於堆疊之引數的解譯方式。 引數和參數之間的類型不符,可能會造成堆疊上的引數解譯不正確。 例如,在 16 位元電腦上,如果將 16 位元指標當成引數傳遞,然後宣告為 long
參數,則堆疊的前 32 個位元會被解譯為 long
參數。 此錯誤不僅會導致 long
參數出現問題,還會導致所有後續參數出現問題。 您可以為所有函式宣告完整的函式原型,來偵測這種錯誤。
原型會建立函式的屬性。 然後,可以檢查函式定義先前的函式呼叫 (或其他來源檔案中發生的函式呼叫) 是否存在引數類型和傳回類型不相符的情況。 例如,若在原型中指定 static
儲存類別指定名稱,則必須同時在函式定義中指定 static
儲存類別。
完整的參數宣告 (int a
) 可以和同一個宣告中的抽象宣告子 (int
) 混用。 例如,下列宣告是合法的:
int add( int a, int );
原型可以包含以引數傳遞之每個運算式的類型和識別項。 不過,這類識別項只會在宣告結尾之前的範圍內。 原型也可以反映引數數目可變或未傳遞任何引數這項事實。 若沒有這種清單,就不會顯示不符,因此編譯器無法產生相關的診斷訊息。 如需類型檢查的詳細資訊,請參閱引數。
現在當使用 /Za
編譯器選項進行編譯時,Microsoft C 編譯器中的原型範圍符合 ANSI 標準。 如果您在原型內宣告 struct
或 union
標記,則會在該範圍中輸入該標記,而不是在全域範圍中輸入。 例如,為遵循 ANSI 標準而使用 /Za
編譯時,若呼叫此函式,一定會出現類型不符錯誤:
void func1( struct S * );
若要修正程式碼,請在函式原型之前於全域範圍定義或宣告 struct
或 union
:
struct S;
void func1( struct S * );
在 /Ze
下,仍然會在全域範圍輸入該標記。