名前空間
変種

関数定義

提供: cppreference.com

関数定義は関数の本体 (宣言と文の並び) を関数名および仮引数リストと紐付けます。 関数宣言と異なり、関数定義はファイルスコープでのみできます (ネストした関数はありません)。

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 - 以下の組み合わせ。
  • 型指定子戻り値の型を形成します (宣言子によって修正される可能性があります)。
  • 記憶域クラス指定子。 識別子のリンケージを決定します (staticextern、または何もなし)。
  • 関数指定子 inline_Noreturn、または何もなし。
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) (C2x未満) 旧形式 (K&R) の関数定義。 この定義はプロトタイプとしては振る舞わず、以後の関数呼び出し式はデフォルト引数昇格を行います。
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__

すべての関数の本体内では、ブロックスコープおよび静的記憶域期間を持つ特別な定義済み変数 __func__ が利用可能です。 これは波括弧の直後に以下のように定義されているかのように振る舞います。

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

この特別な識別子は、例えば assert によって、定義済みマクロ定数 __FILE__ および __LINE__ と組み合わせてよく使用されます。

(C99以上)

ノート

引数リストは宣言子内に明示的に存在しなければならず、 typedef から継承することはできません。

typedef int p(int q, int r); // p は関数型 int(int, int) です。
p f { return q + r; } // エラー。

C89 では、 specifiers-and-qualifiers はオプショナルであり、省略した場合、その関数の戻り値はデフォルトで int になります (宣言子によって修正される場合があります)。

さらに、旧形式の定義では、 declaration-list 内にすべての仮引数に対する宣言は要求されません。 宣言がないあらゆる仮引数は int 型です。

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++リファレンス