定義と宣言の違いは何ですか?


857

両方の意味がわからない。


91
@ラッセ:真実ではない。定義は、定義と宣言の両方を行います;-)
スティーブジェソップ

13
率直に言って、私はそれを学ぶのに多くの問題を抱えていたので、名前を明確に見つけることができませんでした。私は意味に何の問題もありませんでした。意味に関連付ける名前だけです。
David Thornley、

6
それでも、これはC / C ++について尋ねるので、それは重複した質問ではありませんが、他の質問はすべての言語について尋ねるか、一般的には何も尋ねません。答えが重複しているだけです(他の質問では、CやC ++を除くすべての言語を無視するように選択されている回答もあります)。
スティーブジェソップ

5
@DavidThornley私はこのトリックを使用します。定義は、特定の変数または関数のより詳細な説明を提供します。これを思い出すために、「定義」という言葉の真ん中は「精細」という言葉に似ていることを思い出します。:)
マルコ・レオグランデ2012

4
この質問にはどれほどがらくたがありますか。この言語がどれだけ誤解されているかそしてそれらの誤解が日常的にどのように広まっているかを示しに行きます。本当に悲しいです。
オービットのライトネスレース2013年

回答:


858

宣言は、識別子を紹介し、そのタイプを記述し、それはタイプ、オブジェクト、または関数です。宣言は、コンパイラがその識別子への参照を受け入れるために必要なものです。これらは宣言です:

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);

ただし、正確に1回定義する必要があります。宣言され、どこかで参照されているものを定義するのを忘れた場合、リンカは参照をリンクする対象を知らず、不足しているシンボルについて文句を言います。あなたが何かを2回以上定義すると、リンカはどちらを知っいますかへのリンク参照の定義の重複シンボルについて文句を言います。


C ++でのクラス宣言とクラス定義の違いについての議論が(他の質問への回答やコメントで)出続けているので、ここにC ++標準からの引用を貼り付けます。
3.1 / 2では、C ++ 03は次のように述べています。

宣言は、それがクラス名宣言[...]でない限り、定義です。

3.1 / 3では、いくつかの例を示します。それらの中で:

[例:[...]
struct S {int a; int b; }; // S、S :: a、S :: b [...]を定義します
struct S; // Sを宣言します
-終了例

それを要約すると:C ++標準では考慮struct x;することの宣言定義。(つまり、C ++には他の形式のクラス宣言がないため、「前方宣言」は誤称です。)struct x {};

litb(Johannes Schaub)のおかげで、彼の回答の1つで実際の章と詩を掘り下げました。


2
@unknown:コンパイラが壊れているか、sbiのコードが誤ってコピーされています。たとえば、N1124の6.7.2(2):「同じオブジェクトまたは関数を参照するすべての宣言には互換性のある型が必要です。それ以外の場合、動作は未定義です。」
スティーブジェソップ

4
@ブライアン:「extern int i;」私はどこかにintだと言っていますが、心配しないでください。「int i;」iがintであり、そのアドレスとスコープがここで決定されることを意味します。
David Thornley、

12
@ブライアン:あなたは間違っている。extern int iこれは単にを導入/指定するだけなので、宣言iです。extern int i各コンパイルユニットには、必要な数だけ含めることができます。int iただし、定義です。これは、整数がこの変換単位に入るスペースを示し、iこのエンティティーに対するすべての参照をリンクするようリンカーにアドバイスします。これらの定義の1つより多いか少ない場合、リンカは文句を言うでしょう。
sbi 2009

4
int i;ファイル/グローバルスコープまたは関数スコープの@Brian は、CとC ++の両方での定義です。Cではストレージを割り当てるため、C ++ではextern指定子またはリンケージ指定がないため。これらは、sbiが言っていることと同じことになります。どちらの場合でも、この宣言は、そのスコープ内の「i」へのすべての参照をリンクする必要があるオブジェクトを指定します。
スティーブジェソップ

4
@unknown、クラススコープでメンバーを再宣言できないことに注意してください:struct A { double f(int, double); double f(int, double); };もちろん無効です。他の場所でも許可されています。宣言はできるが、定義もできない場所がいくつかあります。void f() { void g(); }有効ですが、次のものはありません。void f() { void g() { } };。テンプレートに関して、定義とは何か、宣言には微妙なルールがあるか-注意してください!良い答えは+1です。
ヨハネスシャウブ-litb 2009

168

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
}

...または typedef or usingステートメントです。

typedef long LONG_32;  // declares LONG_32
using namespace std;   // declares std

ここで、宣言と定義の違いを理解することが重要である大きな理由である、単一定義ルールについて説明します。C ++標準のセクション3.2.1から:

どの翻訳単位にも、変数、関数、クラス型、列挙型、またはテンプレートの複数の定義を含めることはできません。


「クラス定義内で静的メンバーを宣言する」-静的メンバーが初期化されている場合でもこれは正しいですか?例を作れstruct x {static int b = 3; };ますか?
RJFalconer 2014年

@RJFalconerあなたは正しいです。初期化は必ずしも宣言を定義に変えるわけでありませ(予想されることに反して、確かにこれは驚くべきことでした)。bが宣言されていない限り、この例の変更は実際には違法constです。stackoverflow.com/a/3536513/1858225およびdaniweb.com/software-development/cpp/threads/140739/…を参照してください。
カイルストランド

1
これは私にとって興味深いです。あなたの答えによると、C ++では宣言定義を除いて(例外を除いて)いるようですが、C標準では別の観点から(C99、セクション6.7、宣言)と表現されています。「識別子の定義はその識別子の宣言は次のとおりです:[さまざまなケースの基準が続く]。さまざまな見方があると思います。:)
Victor Zamanian 2014年

宣言は、コンパイラが名前を受け入れるためのものです(名前が正当であることをコンパイラに伝えるために、名前はタイプミスではなく意図的に導入されます)。定義は、名前とその内容が関連付けられている場所です。リンカはこの定義を使用して、名前参照を名前のコンテンツにリンクします。
Gab是好人

137

宣言:「どこかにフーがいる」

定義:「...そして、ここにあります!」


3
宣言は、コンパイラが名前を受け入れるためのものです(名前が正当であることをコンパイラに伝えるために、名前はタイプミスではなく意図的に導入されます)。定義は、名前とその内容が関連付けられている場所です。リンカはこの定義を使用して、名前参照を名前のコンテンツにリンクします。
Gab是好人

46

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.

35

宣言

宣言は、プログラムの要素または名前が存在することをコンパイラーに伝えます。宣言は、1つ以上の名前をプログラムに導入します。宣言は、プログラム内で複数回発生する可能性があります。したがって、クラス、構造、列挙型、およびその他のユーザー定義型は、コンパイル単位ごとに宣言できます。

定義

定義は、名前が説明するコードまたはデータを指定します。名前は、使用する前に宣言する必要があります。


ええと、コンパイル単位ごとにクラスや列挙型を定義できるのではないでしょうか。少なくとも、私はクラス定義をヘッダーに入れ、それらをすべて含めます。Er、class foo {}; クラス定義ですでは、されていませんか?
sbi 2009

1
はい。ただし、「クラスfoo;」宣言です。これは、fooがクラスであることをコンパイラーに伝えます。「クラスfoo {};」定義です。これはコンパイラにクラスfooの種類を正確に伝えます。
David Thornley、

1
例外は、宣言される前に使用できるクラスメンバー名です。
Johannes Schaub-litb

1
ええ、それは私が意味したことです。したがって、次のことを実行できます。struct foo {void b(){f(); } void f(); }、fはまだ宣言されていなくても表示されます。次も機能します。struct foo {void b(int = bar()); typedef int bar; } ;. 「すべての関数本体、デフォルトの引数、コンストラクターのctor-initializers」の宣言の前に表示されます。戻り値の型ではありません:(
Johannes Schaub-litb

1
@litb:宣言の前には表示されません。識別子の使用が宣言の背後に移動するだけです。ええ、私は知っています、効果は多くの場合同じです。しかし、すべてのケースに当てはまるわけではないため、正確な説明を使用する必要があると思います。-おっと、待って。デフォルトの引数に表示されますか?まあ、それは確かに私の理解に大混乱をもたらします。くそっ!<pouts>
sbi 2009

22

C99標準から、6.7(5):

宣言は、一連の識別子の解釈と属性を指定します。定義識別子は、その識別子ことの宣言です。

  • オブジェクトの場合、そのオブジェクト用にストレージが予約されます。
  • 関数の場合、関数本体が含まれます。
  • 列挙定数またはtypedef名の場合は、識別子の(唯一の)宣言です。

C ++標準から、3.1(2):

宣言は定義です。ただし、関数の本体を指定せずに関数を宣言し、extern指定子またはリンケージ仕様を含み、初期化子も関数本体も含まない場合、クラス宣言で静的データメンバーを宣言します。クラス名の宣言、またはtypedef宣言、using-declaration、またはusing-directiveです。

次にいくつかの例があります。

興味深いことに(またはそうではありませんが、少し驚いています)、typedef int myint;C99での定義ですが、C ++での宣言のみです。


@onebyone:に関してはtypedef、それがC ++では繰り返されるが、C99では繰り返されないことを意味しませんか?
sbi 2009

それは私を驚かせたものであり、単一の翻訳単位に関する限り、はい、その違いがあります。しかし、明らかにtypedefはC99で異なる翻訳単位で繰り返すことができます。CにはC ++のような明示的な「1つの定義ルール」がないため、Cが持っているルールはそれを許可するだけです。C ++はそれを宣言に変更することを選択しましたが、1つの定義ルールはそれが適用されるものの種類をリストアップし、typedefはそれらの1つではありません。そのため、typedefが定義であったとしても、C ++のODRの下では繰り返しが許可されます。不必要にうるさいようです。
スティーブジェソップ

...しかし、ODRのリストには実際に定義できるすべてのものがリストされていると思います。もしそうなら、リストは実際には冗長であり、参考になるだけです。
スティーブジェソップ

stdのODR定義はクラス定義について何と言っていますか?彼ら繰り返される必要があります。
sbi 2009

2
@sbi:ODRは、「(1)どの変換ユニットにも...クラスタイプの複数の定義を含めることはできません」および「(5)クラスタイプの複数の定義が存在する可能性があります...各定義は異なる翻訳単位で表示されます」、そして「定義は同じ」になる追加の要件
スティーブジェソップ

17

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; 

Answersを参照してください。


3
これは、あまりにも、(はるかに近い他のものよりますが)間違っている:struct foo {};ある定義ではなく宣言。宣言fooになりますstruct foo;。そのため、コンパイラーはfooオブジェクト用に予約するスペースの量を知りません。
sbi 2009

1
@Marcin:sbiは、「このタイプの変数が作成された場合に備えてコンパイラーがどれだけのスペースを確保するかを知っている」とは必ずしも正しくないことを言っています。struct foo;宣言ですが、fooのサイズをコンパイラに伝えません。それstruct _tagExample { int a; int b; };は定義です。したがって、このコンテキストでは、これを宣言と呼ぶのは誤解を招きます。もちろん、すべての定義は宣言なので、1つですが、定義ではないことを示唆しているようです。_tagExampleの定義です。
スティーブジェソップ

1
@Marcin Gil:つまり、 "Answers" wikiは常に正確であるとは限りません。私はここで誤った情報に反対票を投じなければなりません。
David Thornley、

1
引用されたadatapostは真実ですが、実際には(IMO)質問に答えないことがわかります。マーチンが言ったことは誤りです。標準を引用することは真実であり、質問に答えますが、頭または尾を作ることは非常に困難です。
スティーブジェソップ

1
@David Thornley-問題ではありません:)これがこのサイトの目的です。情報選択して確認します。
Marcin Gil、

13

C ++ 11アップデート

C ++ 11に関連する答えが見当たらないので、ここに答えがあります。

a / nを宣言しない限り、宣言は定義です。

  • 不透明な列挙型- enum X : int;
  • テンプレートパラメータ-T intemplate<typename T> class MyArray;
  • パラメータ宣言- XYint add(int x, int y);
  • エイリアス宣言- using IntVector = std::vector<int>;
  • 静的アサート宣言- static_assert(sizeof(int) == 4, "Yikes!")
  • 属性宣言(実装定義)
  • 空の宣言 ;

上記のリストによってC ++ 03から継承された追加の句:

  • 関数宣言- 追加int add(int x, int y);
  • 宣言またはリンケージ指定子を含むextern指定子- extern int a;またはextern "C" { ... };
  • クラスの静的データメンバー-xclass 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

6

定義:

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);
}

2
int a; //declaration; a=10; //definitionこれは完全に間違っています。自動ストレージ期間オブジェクト(externなどの別のストレージクラス指定子で宣言されていない関数定義内で宣言されたオブジェクト)について話すとき、これらは常に定義です。
ジョーイパバリナス2018

把握すべき主な違いは、宣言が「これらの特性(タイプなど)を持つものがどこかに存在する」と言っているのに対し、定義は「これらの特性を持つものを宣言しているので、ここでインスタンス化しています」上手。" このように自動ストレージ期間オブジェクトを転送宣言することはできないため、これらは常に定義になります。
ジョーイパバリナス2018

私がいつも忘れているいくつかの奇妙なtypedefコーナーケースを除いて、経験則では、すべての定義は宣言です。それについて考えてください。何かをインスタンス化するときは、その存在が存在し、その特性が正しいことをコンパイラに伝える必要もあります。
ジョーイパバリナス2018

最初のコメントに従って回答を更新しました。ただし、「何かをインスタンス化しているときは、その存在をコンパイラに通知する必要もあります」というこのコメントには同意しません。インスタンス化するときに、常にlhsのタイプを指定するわけではありません。例:a = 10。ここでは「特性」を指定していません。
SRIDHARAN

4

定義は、実際の関数が記述されていることを意味し、宣言は、たとえば、関数を単純に宣言することを意味します

void  myfunction(); //this is simple declaration

そして

void myfunction()
{
 some statement;    
}

これは関数myfunctionの定義です


1
そして、型とオブジェクトはどうですか?
sbi 2013

4

経験則:

  • 宣言は、メモリ内の変数のデータをどのように解釈するかをコンパイラに指示します。これは、すべてのアクセスに必要です。

  • 定義は、変数が既存にするためにメモリを予約します。これは、最初のアクセスの前に正確に1回発生する必要があります。


2
これはオブジェクトにのみ当てはまります。タイプと関数はどうですか?
オービットのライトネスレース

4

名詞を理解するために、まず動詞に焦点を当てましょう。

宣言 -正式に発表すること。宣言する

定義 -(誰かまたは何か)を明確かつ完全に表示または説明する

したがって、何かを宣言するときは、それが何であるかを伝えるだけです

// declaration
int sum(int, int);

この行は、型の2つの引数を取り、を返す、呼び出されたC関数を宣言しています。ただし、まだ使用できません。sumintint

実際にどのように機能するを提供すると、それがその定義になります。

// definition
int sum(int x, int y)
{
    return x + y;
}

3

宣言と定義の違いを理解するには、アセンブリコードを確認する必要があります。

uint8_t   ui8 = 5;  |   movb    $0x5,-0x45(%rbp)
int         i = 5;  |   movl    $0x5,-0x3c(%rbp)
uint32_t ui32 = 5;  |   movl    $0x5,-0x38(%rbp)
uint64_t ui64 = 5;  |   movq    $0x5,-0x10(%rbp)
double   doub = 5;  |   movsd   0x328(%rip),%xmm0        # 0x400a20
                        movsd   %xmm0,-0x8(%rbp)

これは単なる定義です:

ui8 = 5;   |   movb    $0x5,-0x45(%rbp)
i = 5;     |   movl    $0x5,-0x3c(%rbp)
ui32 = 5;  |   movl    $0x5,-0x38(%rbp)
ui64 = 5;  |   movq    $0x5,-0x10(%rbp)
doub = 5;  |   movsd   0x328(%rip),%xmm0        # 0x400a20
               movsd   %xmm0,-0x8(%rbp)

ご覧のとおり、変化はありません。

宣言はコンパイラによってのみ使用される情報を提供するため、定義とは異なります。たとえば、uint8_tは、asm関数movbを使用するようコンパイラーに指示します。

それを見てください:

uint def;                  |  no instructions
printf("some stuff...");   |  [...] callq   0x400450 <printf@plt>
def=5;                     |  movb    $0x5,-0x45(%rbp)

宣言は実行するものではないため、同等の命令はありません。

さらに、宣言は変数のスコープをコンパイラーに伝えます。

宣言は、変数の正しい使用を確立するためにコンパイラーが使用する情報であり、一部のメモリーが特定の変数に属している期間です。


2

可能な最も一般的な用語で、宣言はストレージが割り当てられていない識別子であり、定義は宣言された識別子から実際にストレージを割り当てると述べられませんか?

1つの興味深い考え-テンプレートは、クラスまたは関数が型情報とリンクされるまで、ストレージを割り当てることができません。テンプレート識別子は宣言または定義ですか?ストレージは割り当てられておらず、テンプレートクラスまたは関数を単に「プロトタイプ化」しているだけなので、宣言である必要があります。


1
あなたの定義自体は間違っていませんが、「ストレージ定義」は関数定義に関しては常に扱いにくいように見えます。テンプレートについて:これtemplate<class T> struct foo;はテンプレート宣言であり、これもテンプレート宣言template<class T> void f();です。テンプレート定義は、クラス/関数定義を同じ方法でミラーリングします。(テンプレート名タイプまたは関数名ではないことに注意してください。これを確認できる場所の1つは、テンプレートを別のテンプレートのタイプパラメータとして渡すことができない場合です。タイプではなくテンプレートを渡す場合は、テンプレートテンプレートパラメータが必要です。 )
sbi 2009

「ストレージ定義」は、特に関数定義に関して、扱いにくいことに同意しました。宣言はint foo()で、定義はint foo(){//ここのコードです。.}。私は通常、私がよく知っている概念で私の小さな脳をラップする必要があります-「ストレージ」は、少なくとも私にそれをまっすぐに保つためのそのような方法の1つです... :)

2

ここで同様の答えを見つけてください:Cの技術面接の質問

宣言プログラムに名前を提供します。定義は、プログラム内のエンティティ(例えばタイプ、インスタンス、および関数)の固有の説明を提供します。宣言は特定のスコープで繰り返すことができ、それは特定のスコープに名前を導入します。

次の場合を除き、宣言は定義です。

  • 宣言は本体を指定せずに関数を宣言し、
  • 宣言には、extern指定子が含まれ、初期化子または関数本体は含まれません。
  • 宣言は、クラス定義のない静的クラスデータメンバーの宣言です。
  • 宣言はクラス名の定義であり、

以下の場合を除き、定義は宣言です。

  • 定義は静的クラスデータメンバーを定義します。
  • 定義は非インラインメンバー関数を定義します。

1

これは本当に安っぽく聞こえますが、それは私が頭の中で用語をまっすぐに保つことができた最良の方法です:

宣言:トーマスジェファーソンがスピーチをしている写真...「このFOOがこのソースコードに存在することをここに宣言します!!!」

定義:辞書を描きます。Fooとその意味を調べています。


1

宣言は、コンパイラにシンボル名を示します。定義は、シンボルにスペースを割り当てる宣言です。

int f(int x); // function declaration (I know f exists)

int f(int x) { return 2*x; } // declaration and definition

1

GNU Cライブラリのマニュアルによると(http://www.gnu.org/software/libc/manual/html_node/Header-Files.html

Cでは、宣言は、関数または変数が存在し、その型を与えるという情報を提供するだけです。関数宣言の場合、その引数の型に関する情報も提供される場合があります。宣言の目的は、コンパイラが宣言された変数と関数への参照を正しく処理できるようにすることです。一方、定義は、実際に変数にストレージを割り当てるか、関数が何をするかを示します。


0

externストレージクラスを使用している場合、宣言が別の場所にあり、ローカルコードファイル(ページ)で変数を宣言しているため、宣言と定義の概念は落とし穴を形成します。CとC ++の違いの1つは、Cでは宣言が関数またはコードページの先頭で通常行われることです。C ++ではそうではありません。好きな場所で申告できます。


1
これは宣言と定義を混同し、明らかに間違っています。
sbi 2015

0

私のお気に入りの例は「int Num = 5」です。ここで、変数は1. intとして定義されます。2。Numとして宣言され、3。値5でインスタンス化されます。我々

  • オブジェクトのタイプを定義します。オブジェクトのタイプは、組み込み、クラス、構造体のいずれでもかまいません。
  • オブジェクトの名前を宣言するので、変数、関数などを含む名前のあるものが宣言されます。

クラスまたは構造体を使用すると、後で使用するときにオブジェクトを定義する方法を変更できます。例えば

  • 特に定義されていない異種変数または配列を宣言できます。
  • C ++でオフセットを使用すると、宣言された名前を持たないオブジェクトを定義できます。

私たちがプログラミングを学ぶとき、私たちはしばしば両方を同時に行うので、これら2つの用語はしばしば混乱します。


なぜ多くの人がsbiの答えに賛成したのか理解できません。私はbjhendの回答に賛成票を投じました。これは、私のものよりも非常に優れており、簡潔で、正確で、よりタイムリーでした。私が4年ぶりにそうしたのを見て私は悲しかった。
Jason K.

0

実行可能な世代の段階:

(1)プリプロセッサ->(2)トランスレータ/コンパイラ->(3)リンカ

ステージ2(トランスレーター/コンパイラー)では、コード内の宣言ステートメントは、将来これらを使用する予定であり、後で定義を見つけることができることをコンパイラーに伝えます。意味は次のとおりです。

翻訳者が確認すること:何とは何ですか?宣言を意味する

(3)ステージ(リンカー)には、物事をバインドするための定義が必要です

リンカーは次のことを確認してください定義を意味する


0

K&R(第2版)全体にいくつかの非常に明確な定義が散りばめられています。それらを1つの場所に置き、1つとして読むと役立ちます。

「定義」とは、変数が作成または割り当てられるストレージを指します。「宣言」とは、変数の性質が記述されているが、ストレージが割り当てられていない場所を指します。[p。33]

...

外部変数の宣言とその定義を区別することが重要です。宣言は、変数(主にその型)のプロパティを通知します。定義により、ストレージも確保されます。行の場合

int sp;
double val[MAXVAL]

任意の関数の外に現れ、彼らが定義する外部変数をspvalストレージを脇に置き、そのソースファイルの残りの部分の宣言としても機能します。

一方、行

extern int sp;
extern double val[];

宣言したソースファイルの残りのためspint、それはvalありますdouble(そのサイズは他の場所で決定される)の配列が、彼らは彼らのために変数や予備記憶を作成しないでください。

ソースプログラムを構成するすべてのファイルの中で、外部変数の定義は1つだけでなければなりません。...配列サイズは定義で指定する必要がありますが、extern宣言ではオプションです。[pp。80-81]

...

宣言は、各識別子に与えられる解釈を指定します。識別子に関連付けられたストレージを必ずしも予約するわけではありません。ストレージを予約する宣言は、定義と呼ばれます。[p。210]


-1

宣言とは、変数に名前と型を与えることを意味します(変数宣言の場合)。例:

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;    
} 

上記の場合、変数iand を定義して宣言しますfunction max()


値/本体を変数/関数に割り当てる場合の定義の実際の平均。宣言手段は名前、型を変数/関数に提供する
Puneet Purohit

値を割り当てずに何かを定義できます。
オービットのライトネスレース


その定義ではなく変数xの宣言
Puneet Purohit 2013

2
いいえ、両方です。定義を初期化と混同しています。
オービットのライトネスレース2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.