名稱空間
變體
操作

函式定義

來自 cppreference.com
< c‎ | language

函式定義將函式體(一系列宣告和語句)與函式名和引數列表關聯起來。與函式宣告不同,函式定義只允許在檔案作用域內(沒有巢狀函式)。

C 支援兩種不同形式的函式定義

attr-spec-seq(可選) specifiers-and-qualifiers parameter-list-declarator function-body (1)
specifiers-and-qualifiers identifier-list-declarator declaration-list function-body (2) (直至 C23)

其中

屬性說明序列 - (C23)應用於函式的屬性的可選列表
specifiers-and-qualifiers - 以下各項的組合
parameter-list-declarator - 用於函式型別的宣告符,它使用引數列表來指定函式引數
identifier-list-declarator - 用於函式型別的宣告符,它使用識別符號列表來指定函式引數
declaration-list - 宣告序列,宣告identifier-list-declarator中的每個識別符號。這些宣告不能使用初始化器,並且唯一允許的儲存類說明符register
function-body - 一個複合語句,即一個用大括號括起來的宣告和語句序列,每當呼叫此函式時都會執行
1) 新式(C89)函式定義。此定義既引入了函式本身,又作為任何未來函式呼叫表示式的函式原型,強制將引數表示式轉換為宣告的引數型別。
int max(int a, int b)
{
    return a>b?a:b;
}
 
double g(void)
{
    return 0.1;
}
2) (直至 C23) 舊式(K&R)函式定義。此定義不作為原型,任何未來的函式呼叫表示式都將執行預設引數提升。
int max(a, b)
int a, b;
{
    return a>b?a:b;
}
double g()
{
    return 0.1;
}

目錄

[編輯] 解釋

函式宣告一樣,函式的返回型別(由specifiers-and-qualifiers中的型別說明符決定,並可能像宣告中通常那樣被declarator修改)必須是完整的非陣列物件型別或void型別。如果返回型別是 cvr-qualified,則為了建構函式型別,它會調整為非限定版本。

void f(char *s) { puts(s); } // return type is void
int sum(int a, int b) { return a+b; } // return type is int
int (*foo(const void *p))[3] { // return type is pointer to array of 3 int
    return malloc(sizeof(int[3]));
}

函式宣告一樣,為了建構函式型別,引數的型別會從函式調整為指標,從陣列調整為指標,並且為了確定相容函式型別,所有引數型別的頂層 cvr-限定符都被忽略。

函式宣告不同,不允許使用未命名的形式引數(否則,舊式 (K&R) 函式定義中會出現衝突),即使它們在函式中未使用,也必須命名。唯一的例外是特殊引數列表(void)

(直至 C23)

形式引數在函式定義中可以不命名,因為舊式(K&R)函式定義已被移除。未命名的引數在函式體內無法透過名稱訪問。

(自 C23 起)
int f(int, int); // declaration
// int f(int, int) { return 7; } // Error until C23, OK since C23
int f(int a, int b) { return 7; } // definition
int g(void) { return 8; } // OK: void doesn't declare a parameter

在函式體內,每個命名引數都是一個左值表示式,它們具有自動儲存期塊作用域。引數在記憶體中的佈局(或者它們是否儲存在記憶體中)未指定:它是呼叫約定的一部分。

int main(int ac, char **av)
{
    ac = 2; // parameters are lvalues
    av = (char *[]){"abc", "def", NULL};
    f(ac, av);
}

有關函式呼叫機制的其他詳細資訊,請參見函式呼叫運算子,有關從函式返回的資訊,請參見return

__func__

在每個函式體內,特殊預定義變數__func__,具有塊作用域和靜態儲存期,可用,如同緊接在開大括號後由以下內容定義:

static const char __func__[] = "function name";

此特殊識別符號有時與預定義宏常量__FILE____LINE__結合使用,例如,由assert使用。

(C99 起)

[編輯] 注意

引數列表必須明確地出現在宣告符中,不能從 typedef 繼承

typedef int p(int q, int r); // p is a function type int(int, int)
p f { return q + r; } // Error

在 C89 中,specifiers-and-qualifiers 是可選的,如果省略,函式的返回型別預設為int(可能由declarator修改)。

此外,舊式定義不需要為declaration-list中的每個引數提供宣告。任何缺少宣告的引數都具有int型別

max(a, b) // a and b have type int, return type is int
{
    return a>b?a:b;
}
(直到 C99)

[編輯] 缺陷報告

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

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

[編輯] 參考

  • C17 標準 (ISO/IEC 9899:2018)
  • 6.9.1 函式定義 (p: 113-115)
  • C11 標準 (ISO/IEC 9899:2011)
  • 6.9.1 函式定義 (p: 156-158)
  • C99 標準 (ISO/IEC 9899:1999)
  • 6.9.1 函式定義 (p: 141-143)
  • C89/C90 標準 (ISO/IEC 9899:1990)
  • 3.7.1 函式定義

[編輯] 另請參閱

C++ 文件,關於函式定義