関数定義
関数定義は関数の本体 (宣言と文の並び) を関数名および仮引数リストと紐付けます。 関数宣言と異なり、関数定義はファイルスコープでのみできます (ネストした関数はありません)。
C は2つの異なる形式の関数定義をサポートしています。
| specifiers-and-qualifiers parameter-list-declarator function-body | (1) | ||||||||
| specifiers-and-qualifiers identifier-list-declarator declaration-list function-body | (2) | (C2x未満) | |||||||
ただし
| specifiers-and-qualifiers | - | 以下の組み合わせ。 |
| parameter-list-declarator | - | 関数の仮引数を表すために仮引数リストを使用する関数型のための宣言子。 |
| identifier-list-declarator | - | 関数の仮引数を表すために識別子リストを使用する関数型のための宣言子。 |
| declaration-list | - | identifier-list-declarator 内のすべての識別子を宣言する宣言の並び。 これらの宣言は初期化子を使用することはできず、使用できる記憶域クラス指定子は register だけです。
|
| function-body | - | 複文、すなわち、波括弧で囲まれた宣言と文の並び。 関数が呼ばれた時に実行されます。 |
int max(int a, int b)
{
return a>b?a:b;
}
double g(void)
{
return 0.1;
}
int max(a, b)
int a, b;
{
return a>b?a:b;
}
double g()
{
return 0.1;
}
説明
関数宣言と同様に、関数の戻り値の型 (specifiers-and-qualifiers の型指定子によって決定され、宣言内の declarator によって通常通りに修正される可能性があります) は、完全非配列オブジェクト型または void 型でなければなりません。
void f(char *s) { puts(s); } // 戻り値の型は void です。
int sum(int a, int b) { return a+b: } // 戻り値の型は int です。
int (*foo(const void *p))[3] { // 戻り値の型は int 3個の配列へのポインタです。
return malloc(sizeof(int[3]));
}
|
関数宣言と同様に、戻り値の型が cvr 修飾されている場合、関数型を構築する目的のためには、それはその修飾されていないバージョンに調節されます。 |
(C17以上) |
関数宣言と同様に、仮引数の型は、関数型を構築する目的のためには、関数からポインタへおよび配列からポインタへ調節され、すべての仮引数の型のトップレベルの cvr 修飾子は、互換な関数型を決定する目的のためには、無視されます。
関数宣言と異なり、名前のない仮引数は使用できず、たとえ関数内で使用されないとしても、名前が必要です。 唯一の例外は特別な仮引数リスト (void) です。
int f(int, int); // 宣言。
// int f(int, int) { return 7; } // エラー。
int f(int a, int b) { return 7; } // 定義。
int g(void) { return 8; } // OK、 void は仮引数を宣言しません。
関数の本体内では、すべての仮引数は左辺値式であり、自動記憶域期間およびブロックスコープを持ちます。 メモリ内の仮引数のレイアウト (また、そもそもメモリ内に格納されるのかどうか) は未規定です (それらは呼び出し規約の一部です)。
int main(int ac, char **av)
{
ac = 2; // 仮引数は左辺値です。
av = (char *[]){"abc", "def", NULL};
f(ac, av);
}
関数呼び出しの仕組みに関するその他の詳細については{rlp|operator_other#Function_call|関数呼び出し演算子}}を、関数からの戻りについては return 文を参照してください。
__func__すべての関数の本体内では、ブロックスコープおよび静的記憶域期間を持つ特別な定義済み変数 static const char __func__[] = "function name";
この特別な識別子は、例えば assert によって、定義済みマクロ定数 |
(C99以上) |
ノート
引数リストは宣言子内に明示的に存在しなければならず、 typedef から継承することはできません。
typedef int p(int q, int r); // p は関数型 int(int, int) です。
p f { return q + r; } // エラー。
|
C89 では、 specifiers-and-qualifiers はオプショナルであり、省略した場合、その関数の戻り値はデフォルトで さらに、旧形式の定義では、 declaration-list 内にすべての仮引数に対する宣言は要求されません。 宣言がないあらゆる仮引数は max(a, b) // a と b は int 型であり、戻り値の型は int です。
{
return a>b?a:b;
}
|
(C99未満) |
参考文献
- C11 standard (ISO/IEC 9899:2011):
- 6.9.1 Function definitions (p: 156-158)
- C99 standard (ISO/IEC 9899:1999):
- 6.9.1 Function definitions (p: 141-143)
- C89/C90 standard (ISO/IEC 9899:1990):
- 3.7.1 Function definitions
関連項目
関数定義 の C++リファレンス
|