名稱空間
變體
操作

函式宣告

來自 cppreference.com
< c‎ | 語言

函式宣告引入一個識別符號,用於指定一個函式,並可選地指定函式引數的型別(即原型)。函式宣告(與函式定義不同)可以出現在塊作用域以及檔案作用域中。

目錄

[編輯] 語法

在函式宣告的宣告語法中,型別說明符序列(可能由宣告符修改)指定返回型別(可以是除陣列或函式型別以外的任何型別),並且宣告符有以下三種形式之一:

noptr-declarator ( parameter-list ) attr-spec-seq(可選) (1)
noptr-declarator ( identifier-list ) attr-spec-seq(可選) (2) (直至 C23)
noptr-declarator ( ) attr-spec-seq(可選) (3)

其中

noptr-declarator - 任何宣告符,除了未加括號的指標宣告符。此宣告符中包含的識別符號成為函式指定符。
parameter-list - 單個關鍵字void或逗號分隔的引數列表,列表末尾可以是一個省略號引數
identifier-list - 逗號分隔的識別符號列表,僅當此宣告符用作舊式函式定義的一部分時才可能出現
屬性說明序列 - (C23)可選的屬性列表,應用於函式型別
1) 新式 (C89) 函式宣告。此宣告既引入函式指定符本身,又作為任何未來函式呼叫表示式的函式原型,強制引數表示式轉換為宣告的引數型別,並進行編譯時引數數量檢查。
int max(int a, int b); // declaration
int n = max(12.01, 3.14); // OK, conversion from double to int
2) (C23 前) 舊式 (K&R) 函式定義。此宣告不引入原型,任何未來函式呼叫表示式將執行預設引數提升,如果引數數量與形引數量不匹配,將導致未定義行為。
int max(a, b) 
    int a, b; // definition expects ints; the second call is undefined
{
    return a > b ? a : b;
}
 
int n = max(true, (char)'a'); // calls max with two int args (after promotions)
 
int n = max(12.01f, 3.14); // calls max with two double args (after promotions)
3) 非原型函式宣告。此宣告不引入原型(C23 前)一種新式函式宣告,等同於引數列表void(C23 起)

[編輯] 解釋

函式的返回型別,由說明符和限定符中的型別說明符確定,並可能像宣告中通常一樣由宣告符修改,必須是非陣列物件型別或void型別。如果函式宣告不是定義,則返回型別可以是不完整型別。返回型別不能是 cvr 限定的:任何限定的返回型別在構建函式型別時都會調整為其非限定版本。

void f(char *s);                    // return type is void
int sum(int a, int b);              // return type of sum is int.
int (*foo(const void *p))[3];       // return type is pointer to array of 3 int
 
double const bar(void);             // declares function of type double(void)
double (*barp)(void) = bar;         // OK: barp is a pointer to double(void)
double const (*barpc)(void) = barp; // OK: barpc is also a pointer to double(void)

函式宣告符可以與其他宣告符結合使用,只要它們可以共享其型別說明符和限定符

int f(void), *fip(), (*pfi)(), *ap[3]; // declares two functions and two objects
inline int g(int), n; // Error: inline qualifier is for functions only
typedef int array_t[3];
array_t a, h(); // Error: array type cannot be a return type for a function

如果函式宣告出現在任何函式之外,它引入的識別符號具有檔案作用域外部連結,除非使用了static或者可見更早的靜態宣告。如果宣告出現在另一個函式內部,該識別符號具有塊作用域(並且具有內部或外部連結)。

int main(void)
{
    int f(int); // external linkage, block scope
    f(1); // definition needs to be available somewhere in the program
}

宣告中的引數如果不是函式定義的一部分(C23 前)不需要命名

int f(int, int); // declaration
// int f(int, int) { return 7; } // Error: parameters must be named in definitions
// This definition is allowed since C23

引數列表中的每個引數都是一個引入單個變數的宣告,具有以下附加屬性:

  • 宣告符中的識別符號是可選的(除非此函式宣告是函式定義的一部分)(C23 前)
int f(int, double); // OK
int g(int a, double b); // also OK
// int f(int, double) { return 1; } // Error: definition must name parameters
// This definition is allowed since C23
  • 引數允許的唯一儲存類說明符register,並且在非定義的函式宣告中它被忽略
int f(static int x); // Error
int f(int [static 10]); // OK (array index static is not a storage class specifier)
  • 任何陣列型別的引數都調整為相應的指標型別,如果陣列宣告符的方括號之間有限定符,則指標型別也可以是限定的(C99 起)
int f(int[]); // declares int f(int*)
int g(const int[10]); // declares int g(const int*)
int h(int[const volatile]); // declares int h(int * const volatile)
int x(int[*]); // declares int x(int*)
  • 任何函式型別的引數都調整為相應的指標型別
int f(char g(double)); // declares int f(char (*g)(double))
int h(int(void)); // declares int h(int (*)(void))
int f(int, ...);
  • 引數不能是void型別(但可以是void的指標型別)。完全由關鍵字void組成的特殊引數列表用於宣告不帶引數的函式。
int f(void); // OK
int g(void x); // Error
  • 引數列表中出現的任何可以被視為 typedef 名稱或引數名稱的識別符號都被視為 typedef 名稱:int f(size_t, uintptr_t) 被解析為宣告一個接受兩個無名引數(型別分別為 size_t 和 uintptr_t)的函式的新式宣告符,而不是一個以“size_t”和“uintptr_t”為引數名開始函式定義的舊式宣告符。
  • 引數可以具有不完整型別,並且可以使用 VLA 記號 [*](C99 起)(但在函式定義中,經過陣列到指標和函式到指標調整後的引數型別必須是完整型別)

屬性說明符序列也可以應用於函式引數。

(自 C23 起)

關於函式呼叫機制的其他細節,請參見函式呼叫運算子;關於從函式返回,請參見return

[編輯] 注意

與 C++ 不同,宣告符 f()f(void) 具有不同的含義:宣告符 f(void) 是一個新式(原型)宣告符,宣告一個不帶引數的函式。宣告符 f() 是一個宣告帶未指定數量引數的函式(除非用於函式定義)

int f(void); // declaration: takes no parameters
int g(); // declaration: takes unknown parameters
 
int main(void) {
    f(1); // compile-time error
    g(2); // undefined behavior
}
 
int f(void) { return 1; } // actual definition
int g(a,b,c,d) int a,b,c,d; { return 2; } // actual definition
(直至 C23)

函式定義不同,引數列表可以從 typedef 繼承

typedef int p(int q, int r); // p is a function type int(int, int)
p f; // declares int f(int, int)

在 C89 中,說明符和限定符是可選的,如果省略,函式的返回型別預設為int(可能由宣告符修改)。

*f() { // function returning int*
   return NULL;
}
(直到 C99)

[編輯] 缺陷報告

以下行為改變的缺陷報告被追溯地應用於以前釋出的 C 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
DR 423 C89 返回型別可能被限定 返回型別被隱式取消限定

[編輯] 參考文獻

  • C17 標準 (ISO/IEC 9899:2018)
  • 6.7.6.3 函式宣告符(包括原型)(p: 96-98)
  • C11 標準 (ISO/IEC 9899:2011)
  • 6.7.6.3 函式宣告符(包括原型)(p: 133-136)
  • C99 標準 (ISO/IEC 9899:1999)
  • 6.7.5.3 函式宣告符(包括原型)(p: 118-121)
  • C89/C90 標準 (ISO/IEC 9899:1990)
  • 3.5.4.3 函式宣告符(包括原型)

[編輯] 另請參閱

C++ 文件關於函式宣告