両方の意味がわかりません。
25 に答える
宣言は識別子を導入し、型、オブジェクト、関数などの型を記述します。宣言は、コンパイラがその識別子への参照を受け入れるために必要なものです。これらは宣言です:
extern int bar;
extern int g(int, int);
double f(int, double); // extern can be omitted for function declarations
class foo; // no extern allowed for type declarations
定義は、実際にこの識別子をインスタンス化/実装します。これらのエンティティへの参照をリンクするためにリンカーが必要とするものです。これらは、上記の宣言に対応する定義です。
int bar;
int g(int lhs, int rhs) {return lhs*rhs;}
double f(int i, double d) {return i+d;}
class foo {};
宣言の代わりに定義を使用できます。
識別子は何度でも宣言できます。したがって、以下は C および C++ で有効です。
double f(int, double);
double f(int, double);
extern double f(int, double); // the same as the two above
extern double f(int, double);
ただし、一度だけ定義する必要があります。宣言されてどこかで参照されているものを定義するのを忘れた場合、リンカーは参照をリンクするものを認識せず、シンボルが見つからないと文句を言います。何かを複数回定義すると、リンカーは参照をリンクする定義を認識せず、シンボルの重複について不平を言います。
C++ のクラス宣言とクラス定義とは何かという議論が続いているので(他の質問への回答とコメントで)、C++ 標準からの引用をここに貼り付けます。
3.1/2 で、C++03 は次のように述べています。
[...] クラス名宣言 [...] でない限り、宣言は定義です。
次に、3.1/3 でいくつかの例を示します。それらの中で:
[例: [...] 構造体 S { int a; int b; }; // S、S::a、および S::b を定義 [...] 構造体 S; // S を宣言 — 例の終わり
要約すると、C++ 標準でstruct x;
は、宣言と定義が考慮されます。(つまり、C++ には他の形式のクラス宣言がないため、 「前方宣言」は誤称です。)struct x {};
回答の 1 つで実際の章と節を掘り下げてくれたlitb (Johannes Schaub)に感謝します。
C++ 標準セクション 3.1 から:
宣言は、名前を翻訳単位に導入するか、以前の宣言によって導入された名前を再宣言します。宣言は、これらの名前の解釈と属性を指定します。
次の段落では、宣言は定義であると述べています...
... 関数の本体を指定せずに関数を宣言します。
void sqrt(double); // declares sqrt
... クラス定義内で静的メンバーを宣言します。
struct X
{
int a; // defines a
static int b; // declares b
};
... クラス名を宣言します。
class Y;
...extern
初期化子または関数本体のないキーワードが含まれています:
extern const int i = 0; // defines i
extern int j; // declares j
extern "C"
{
void foo(); // declares foo
}
... or はtypedef
orusing
ステートメントです。
typedef long LONG_32; // declares LONG_32
using namespace std; // declares std
ここで、宣言と定義の違いを理解することが重要である大きな理由について説明します。One Definition Ruleです。C++ 標準のセクション 3.2.1 から:
変換単位には、変数、関数、クラス型、列挙型、またはテンプレートの複数の定義が含まれてはなりません。
宣言: 「どこかに foo が存在します。」
定義: 「...そしてここにある!」
C++ には興味深いエッジ ケースがあります (一部は C にもあります)。検討
T t;
型に応じて、定義または宣言になる可能性がありますT
。
typedef void T();
T t; // declaration of function "t"
struct X {
T t; // declaration of function "t".
};
typedef int T;
T t; // definition of object "t".
C++ でテンプレートを使用する場合、別のエッジ ケースがあります。
template <typename T>
struct X {
static int member; // declaration
};
template<typename T>
int X<T>::member; // definition
template<>
int X<bool>::member; // declaration!
最後の宣言は定義ではありませんでした。の静的メンバーの明示的な特殊化の宣言ですX<bool>
。コンパイラに次のように伝えますX<bool>::member
。定義にするには、初期化子を指定する必要があります
template<>
int X<bool>::member = 1; // definition, belongs into a .cpp file.
宣言
宣言は、プログラム要素または名前が存在することをコンパイラに伝えます。宣言は、1 つまたは複数の名前をプログラムに導入します。宣言は、プログラム内で複数回発生する可能性があります。したがって、クラス、構造体、列挙型、およびその他のユーザー定義型は、コンパイル単位ごとに宣言できます。
意味
定義は、名前が表すコードまたはデータを指定します。名前は、使用する前に宣言する必要があります。
C99標準から、6.7(5):
宣言は、一連の識別子の解釈と属性を指定します。識別子の定義は、次のような識別子の宣言です。
- オブジェクトの場合、ストレージはそのオブジェクト用に予約されます。
- 関数の場合、関数本体を含みます。
- 列挙定数またはtypedef名の場合、は識別子の(唯一の)宣言です。
C ++標準、3.1(2)から:
宣言は、関数の本体を指定せずに関数を宣言し、extern指定子またはリンケージ仕様を含み、初期化子も関数本体も含まない場合を除き、定義です。クラス宣言で静的データメンバーを宣言します。クラス名宣言、またはtypedef宣言、using宣言、またはusingディレクティブです。
次に、いくつかの例があります。
非常に興味深いことに(またはそうではありませんが、少し驚いていますが)、typedef int myint;
C99での定義ですが、C++での宣言にすぎません。
wiki.answers.com から:
宣言という用語は、(C では) 型、サイズ、および関数宣言の場合は、変数のパラメーターの型とサイズ、またはプログラム内のユーザー定義型または関数についてコンパイラーに伝えることを意味します。宣言の場合、変数用のメモリ領域は確保されません。ただし、コンパイラは、この型の変数が作成された場合に備えて確保するスペースを知っています。
たとえば、次はすべての宣言です。
extern int a;
struct _tagExample { int a; int b; };
int myFunc (int a, int b);
一方、定義は、宣言が行うすべてのことに加えて、スペースもメモリに予約されることを意味します。「DEFINITION = DECLARATION + SPACE RESERVATION」と言うことができます。以下は定義の例です。
int a;
int b = 0;
int myFunc (int a, int b) { return a + b; }
struct _tagExample example;
回答を参照してください。
C++11 アップデート
C++11 に関連する回答が見当たらないので、ここに回答を示します。
a/n を宣言しない限り、宣言は定義です。
- 不透明な列挙 -
enum X : int;
- テンプレート パラメータ - T in
template<typename T> class MyArray;
- パラメータ宣言 - xとyの
int add(int x, int y);
- 別名宣言 -
using IntVector = std::vector<int>;
- static assert 宣言 -
static_assert(sizeof(int) == 4, "Yikes!")
- 属性宣言 (実装定義)
- 空の宣言
;
上記のリストによって C++03 から継承された追加の節:
- 関数宣言 -追加
int add(int x, int y);
- 宣言またはリンケージ指定子を含む extern 指定子 -
extern int a;
またはextern "C" { ... };
- クラスの静的データ メンバー - x in
class C { static int x; };
- クラス/構造体宣言 -
struct Point;
- typedef 宣言 -
typedef int Int;
- 宣言の使用 -
using std::cout;
- ディレクティブを使用 -
using namespace NS;
テンプレート宣言は宣言です。宣言が関数、クラス、または静的データ メンバーを定義する場合、テンプレート宣言も定義です。
宣言と定義を区別する標準の例は、それらの間のニュアンスを理解するのに役立ちました。
// except one all these are definitions
int a; // defines a
extern const int c = 1; // defines c
int f(int x) { return x + a; } // defines f and defines x
struct S { int a; int b; }; // defines S, S::a, and S::b
struct X { // defines X
int x; // defines non-static data member x
static int y; // DECLARES static data member y
X(): x(0) { } // defines a constructor of X
};
int X::y = 1; // defines X::y
enum { up , down }; // defines up and down
namespace N { int d; } // defines N and N::d
namespace N1 = N; // defines N1
X anX; // defines anX
// all these are declarations
extern int a; // declares a
extern const int c; // declares c
int f(int); // declares f
struct S; // declares S
typedef int Int; // declares Int
extern X anotherX; // declares anotherX
using N::d; // declares N::d
// specific to C++11 - these are not from the standard
enum X : int; // declares X with int as the underlying type
using IntVector = std::vector<int>; // declares IntVector as an alias to std::vector<int>
static_assert(X::y == 1, "Oops!"); // declares a static_assert which can render the program ill-formed or have no effect like an empty declaration, depending on the result of expr
template <class T> class C; // declares template class C
; // declares nothing
意味 :
extern int a; // Declaration
int a; // Definition
a = 10 // Initialization
int b = 10; // Definition & Initialization
定義は変数を型に関連付けてメモリを割り当てますが、宣言は型を指定するだけでメモリを割り当てません。定義前に変数を参照したい場合は、宣言の方が便利です。
*定義と初期化を混同しないでください。どちらも異なり、初期化により変数に値が与えられます。上記の例を参照してください。
以下は定義の例です。
int a;
float b;
double c;
今関数宣言:
int fun(int a,int b);
関数の末尾にあるセミコロンに注意してください。これは宣言にすぎません。コンパイラは、プログラムのどこかでその関数がそのプロトタイプで定義されることを知っています。コンパイラが次のような関数呼び出しを取得した場合
int b=fun(x,y,z);
コンパイラは、そのような関数がないことを示すエラーをスローします。その関数のプロトタイプがないためです。
2 つのプログラムの違いに注意してください。
プログラム 1
#include <stdio.h>
void print(int a)
{
printf("%d",a);
}
main()
{
print(5);
}
この中で、print 関数も宣言および定義されます。関数呼び出しは定義の後に来るので。それでは次のプログラムをご覧ください。
プログラム 2
#include <stdio.h>
void print(int a); // In this case this is essential
main()
{
print(5);
}
void print(int a)
{
printf("%d",a);
}
関数呼び出しは定義に先行するため、コンパイラはそのような関数があるかどうかを知る必要があるため、これは不可欠です。そこで、コンパイラに通知する関数を宣言します。
意味 :
関数を定義するこの部分は、定義と呼ばれます。関数内で何をするかを示します。
void print(int a)
{
printf("%d",a);
}
経験則:
宣言は、メモリ内の変数のデータを解釈する方法をコンパイラに指示します。これは、すべてのアクセスに必要です。
定義は、変数を存在させるためにメモリを予約します。これは、最初のアクセスの前に 1 回だけ発生する必要があります。
定義は書かれた実際の関数を意味し、宣言は例えば単純な宣言関数を意味します
void myfunction(); //this is simple declaration
と
void myfunction()
{
some statement;
}
これは関数 myfunction の定義です
同様の回答をここで見つけてください: Technical Interview Questions in C .
宣言は、プログラムに名前を提供します。定義は、プログラム内のエンティティ (型、インスタンス、関数など) の一意の説明を提供します。宣言は特定のスコープで繰り返すことができ、特定のスコープに名前を導入します。
次の場合を除き、宣言は定義です。
- 宣言は、本体を指定せずに関数を宣言します。
- 宣言に extern 指定子が含まれ、初期化子または関数本体が含まれていない。
- 宣言は、クラス定義のない静的クラス データ メンバーの宣言です。
- 宣言はクラス名の定義であり、
次の場合を除き、定義は宣言です。
- 定義は、静的クラス データ メンバーを定義します。
- Definition は、非インライン メンバー関数を定義します。
可能な限り最も一般的な用語で、宣言はストレージが割り当てられていない識別子であり、定義は宣言された識別子から実際にストレージを割り当てていると言えませんか?
興味深い考えの1つは、クラスまたは関数が型情報にリンクされるまで、テンプレートはストレージを割り当てることができないということです。では、テンプレート識別子は宣言または定義ですか?ストレージが割り当てられておらず、テンプレートクラスまたは関数を単に「プロトタイピング」しているため、これは宣言である必要があります。
宣言は、シンボル名をコンパイラに提示します。定義は、シンボルにスペースを割り当てる宣言です。
int f(int x); // function declaration (I know f exists)
int f(int x) { return 2*x; } // declaration and definition
これは非常に安っぽく聞こえるかもしれませんが、これが用語を頭の中で整理するための最良の方法です。
宣言: トーマス・ジェファーソンがスピーチをしている写真... 「私はここに、このソース コードにこの FOO が存在することを宣言します!!!」
定義: 辞書を思い浮かべてください。Foo とその意味を調べています。
変数の宣言は、次の情報をコンパイラに通知するためのものです: 変数の名前、それが保持する値の型、および初期値がある場合は初期値。つまり、宣言は変数のプロパティに関する詳細を提供します。一方、変数の定義は、変数が格納される場所を示します。つまり、変数のメモリは、変数の定義中に割り当てられます。
宣言は、プリミティブまたはオブジェクト参照変数またはメソッドが、値またはオブジェクトを割り当てずに作成される場合です。int a; 最終的な整数 a;
定義は、値またはオブジェクトをそれぞれ int a =10; に割り当てることを意味します。
初期化とは、それぞれの変数またはオブジェクトにメモリを割り当てることを意味します。
宣言とは、変数に名前と型を与えることを意味します (変数宣言の場合)。例:
int i;
または、本体のない関数に名前、戻り値の型、パラメーターの型を指定します (関数宣言の場合)。例:
int max(int, int);
一方、定義は変数に値を代入することを意味します (変数定義の場合)。
i = 20;
または、関数に本体 (機能) を提供/追加することは、関数定義と呼ばれます。
int max(int a, int b)
{
if(a>b) return a;
return b;
}
多くの場合、次のように宣言と定義を一緒に行うことができます。
int i=20;
と:
int max(int a, int b)
{
if(a>b) return a;
return b;
}
i
上記の場合、変数とを定義して宣言しますfunction max()
。