名前空間
変種
操作

関数宣言

From cppreference.com
< c‎ | language

関数宣言は、関数を示す識別子を導入し、オプションで関数のパラメータの型を指定します(プロトタイプ)。関数宣言(定義とは異なり)は、ブロックスコープおよびファイルスコープで出現できます。

目次

[編集] 構文

関数宣言の宣言文法において、type-specifierのシーケンスは、宣言子によって変更される可能性があり、戻り値の型(配列型または関数型以外の任意の型)を指定します。そしてdeclaratorは次の3つの形式のいずれかを取ります。

noptr-declarator ( parameter-list ) attr-spec-seq(optional) (1)
noptr-declarator ( identifier-list ) attr-spec-seq(optional) (2) (C23まで)
noptr-declarator ( ) attr-spec-seq(optional) (3)

ここで、

noptr-declarator - 括弧で囲まれていないポインタ宣言子以外の、任意の宣言子。この宣言子に含まれる識別子は、関数指定子となる識別子です。
parameter-list - 単一のキーワードvoidまたは、パラメータのコンマ区切りリスト。これは可変長引数で終わる場合があります。
identifier-list - 識別子のコンマ区切りリスト。これは、古いスタイルの関数定義の一部としてこの宣言子が使用されている場合にのみ可能です。
attr-spec-seq - (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まで)parameter-list void(C23以降)に相当する新しいスタイルの関数宣言。

[編集] 説明

specifiers-and-qualifiersの型指定子によって決定され、宣言の通常のdeclaratorによって変更される可能性のある関数の戻り値の型は、非配列オブジェクト型または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が使用されない限り、または以前の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

parameter-listの各パラメータは、単一の変数を導入する宣言ですが、以下の追加プロパティがあります。

  • 宣言子の識別子はオプションです(この関数宣言が関数定義の一部である場合を除く)(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))
  • パラメータリストは, ...で終了する場合があり、または...のみの場合もあります(C23以降)。詳細については、可変長引数関数を参照してください。
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型の2つの名前のないパラメータを取る関数を宣言する新しいスタイルの宣言子として解析され、"size_t"と"uintptr_t"という名前の2つのパラメータを取る関数の定義を開始する古いスタイルの宣言子ではありません。
  • パラメータは不完全型を持つことができます、および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では、specifiers-and-qualifiersはオプションであり、省略された場合、関数の戻り値の型はデフォルトでintdeclaratorによって変更される可能性あり)になりました。

*f() { // function returning int*
   return NULL;
}
(C99まで)

[編集] 欠陥報告

以下の動作変更を伴う欠陥報告が、以前に発行されたC規格に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
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++ドキュメント関数宣言について)
English 日本語 中文(简体) 中文(繁體)