名前空間
変種
操作

宣言

提供: cppreference.com
< c‎ | language

宣言はプログラムにひとつ以上の識別子を導入し、その意味と性質を指定する C の言語構文です。

宣言はどのスコープでも行うことができます。 各々の宣言は (ちょうどと同じように) セミコロンで終わり、2つの別々の部分から構成されます。

specifiers-and-qualifiers declarators-and-initializers ;
specifiers-and-qualifiers - 以下のホワイトスペース区切りのリスト (順不同)
  • 型指定子:
declarators-and-initializers - カンマ区切りの宣言子のリスト (各々の宣言子は追加の型情報や宣言する識別子を提供します)。 宣言子は初期化子を伴っても構いません。 列挙型構造体共用体の宣言では宣言子を省略しても構いません (その場合は列挙定数やタグだけが導入されます)。


以下に例を挙げます。

int a, *b=NULL; // 「int」は型指定子です
                // 「a」は宣言子です
                // 「*b」は宣言子で「NULL」はその初期化子です
const int *f(void); // 「int」は型指定子です
                    // 「const」は型修飾子です
                    // 「*f(void)」は宣言子です
enum COLOR {RED, GREEN, BLUE} c; // 「enum COLOR {RED, GREEN, BLUE}」は型指定子です
                                 // 「c」は宣言子です

宣言によって導入される各々の識別子の型は、型指定子によって指定される型と、その宣言子によって適用される型修飾子の組み合わせで決定されます。

目次

[編集] 宣言子

各々の宣言子は以下のいずれかです。

identifier (1)
( declarator ) (2)
* qualifiers(オプション) declarator (3)
noptr-declarator [ static(オプション) qualifiers(オプション) expression ]

noptr-declarator [ qualifiers(オプション) * ]

(4)
noptr-declarator ( parameters-or-identifiers ) (5)
1) この宣言子が導入する識別子です。
2) 宣言子は括弧で囲っても構いません。 これは配列へのポインタや関数へのポインタを導入する場合に必要です。
3) ポインタ宣言子: 宣言 S * cvr DS によって決まる型への cvr 修飾されたポインタとして D を宣言します。
4) 配列宣言子: 宣言 S D[N]S によって決まる型のオブジェクト N 個の配列として D を宣言します。 noptr-declarator は括弧で囲まれていないポインタ宣言子を除く任意の他の宣言子です。
5) 関数宣言子: 宣言 S D(params) は引数 params を取り戻り値 S を返す関数として D を宣言します。 noptr-declarator は括弧で囲まれていないポインタ宣言子を除く任意の他の宣言子です。

この構文の背後にある理由は、宣言子によって宣言された識別子がその宣言子と同じ形の式で使われたとき、一連の型指定子で指定された型になるということです。

struct C {
    int member; // 「int」は型指定子
                // 「member」は宣言子
} obj, *pObj = &obj;
// 「struct C { int member; }」は型指定子です
// 宣言子「obj」は構造体 C のオブジェクトを定義しています
// 宣言子「*pObj」は C へのポインタを宣言し、
// 初期化子「= &obj」はそのポインタに対して初期値を与えています
 
int a = 1, *p = NULL, f(void), (*pf)(double);
// 型指定子は「int」です
// 宣言子「a」は int 型のオブジェクトを定義しています
//   初期化子「=1」はその初期値を与えています
// 宣言子「*p」は int へのポインタ型のオブジェクトを定義しています
//   初期化子「=NULL」はその初期値を与えています
// 宣言子「f(void)」は void を取り int を返す関数を宣言しています
// 宣言子「(*pf)(double)」は double を取り int を返す関数へのポインタ型のオブジェクトを定義しています
 
int (*(*foo)(double))[3] = NULL;
// 型指定子は int です
// 1. 宣言子「(*(*foo)(double))[3]」は配列宣言子です
//    宣言された内容は「int 3個の配列 *(*foo)(double)」です
// 2. 宣言子「*(*foo)(double)」はポインタ宣言子です
//    宣言された内容は「int 3個の配列へのポインタ (*foo)(double)」です
// 3. 宣言子「(*foo)(double)」は関数宣言子です
//    宣言された内容は「int 3個の配列へのポインタを返し double を取る関数 *foo」です
// 4. 宣言子「*foo」はポインタ宣言子です
//    宣言された内容は「int 3個の配列へのポインタを返し double を取る関数へのポインタ foo」です
// 5. 宣言子「foo」は識別子です
// この宣言は「int 3個の配列へのポインタを返し double を取る関数へのポインタ」型のオブジェクトを参照する識別子「foo」を導入します。
// 初期化子「= NULL」はこのポインタの初期値を与えます。
 
// 「foo」を宣言子の形の式で使用すると、その型は int になります。
int x = (*(*foo)(1.2))[0];

他の宣言子の一部でない宣言子はすべて、副作用完了点の終わりです。

[編集] 定義

定義は、それが宣言する識別子に関するすべての情報を与える宣言です。

列挙型または typedef の宣言はすべて定義です。

関数の場合、関数の本体を含む宣言が関数定義になります。

int foo(double); // 宣言
int foo(double x){ return x; } // 定義

オブジェクトの場合、記憶域 (自動または静的) を確保する宣言が定義で、記憶域を確保しない宣言 (外部宣言) は定義ではありません。

extern int n; // 宣言
int n = 10; // 定義

構造体および共用体の場合、メンバのリストを指定する宣言が定義です。

struct X; // 宣言
struct X { int n; }; // 定義

[編集] 再宣言

宣言は、同じスコープに同じ識別子に対する宣言がすでに存在する場合、その識別子を導入できません。 ただし、以下の場合を除きます。

  • (外部または内部) リンケージ付きのオブジェクトの宣言は繰り返すことができます。
extern int x;
int x = 10; // OK
extern int x; // OK
 
static int n;
static int n = 10; // OK
static int n; // OK
  • VLA でない typedef は同じ型を参照している限り繰り返すことができます。
typedef int int_t; 
typedef int int_t; // OK
struct X;
struct X { int n; };
struct X;

これらのルールはヘッダファイルの使用を単純化します。

[編集] ノート

C89 では、複文 (ブロックスコープ) 内の宣言はブロックの先頭、いかなるよりも前に、現れなければなりません。

また、 C89 では、 int を返す関数は関数呼び出し演算子により暗黙的に定義することができ、旧形式の関数定義を使用するときは int 型の関数引数を宣言する必要がありません。

(C99未満)

空の宣言は禁止されています。 宣言は static_assert 宣言であるか、 (C11以上)少なくとも1個の宣言子を持つか、少なくとも1個の構造体、共用体、列挙型のタグを宣言するか、少なくとも1個の列挙定数を導入しなければなりません。

宣言子の一部または全部に VLA 配列宣言子が含まれている場合、宣言子全体の型は「可変修飾型」と呼ばれます。 可変修飾型から定義された型もまた可変修飾 (variably modified; VM) です。

可変修飾型の宣言はブロックスコープまたは関数プロトタイプスコープにのみ現れることができ、構造体や共用体のメンバになることはできません。 VLA は自動記憶域期間のみ持つことができますが、 VLA へのポインタのような VM 型は静的でも構いません。 VM 型の使用は他にも制限があります。 goto, switch, longjmp を参照してください。

(C99以上)

static_assert は C の文法の観点からは宣言とみなされます (そのため宣言を書ける場所ならどこでも書くことができます) が、いかなる識別子も導入せず、宣言の構文にも従いません。

(C11以上)

[編集] 参考文献

  • C11 standard (ISO/IEC 9899:2011):
  • 6.7 Declarations (p: 108-145)
  • C99 standard (ISO/IEC 9899:1999):
  • 6.7 Declarations (p: 97-130)
  • C89/C90 standard (ISO/IEC 9899:1990):
  • 3.5 Declarations

[編集] 関連項目