web-dev-qa-db-ja.com

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

両方の意味は私を避けます。

790
Maciek

宣言は識別子を導入し、その型を記述します。型、オブジェクト、関数のいずれでもかまいません。その識別子への参照を受け入れるための宣言はコンパイラが必要とするものです。これらは宣言です:

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

しかし、それはdefinedでなければなりません。どこかで宣言され参照されているものを定義するのを忘れた場合、リンカは参照をリンクするものがわからず、見つからないシンボルについて文句を言います。複数回定義した場合、リンカは参照をリンクする定義のwhichを認識せず、重複したシンボルについて文句を言います。


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;宣言struct x {};定義と見なします。 (つまり、C++には他の形式のクラス宣言はないため、"前方宣言"の誤称となります。)

litb(Johannes Schaub) のおかげで、実際の章を掘り下げ、彼の答えの1つを読んだ。

801
sbi

C++標準のセクション3.1から:

declarationは、名前を翻訳単位に導入するか、または以前の宣言によって導入された名前を再宣言します。宣言はこれらの名前の解釈と属性を指定します。

次の段落では、次の場合を除き、宣言定義であるを強調しています(強調)。

...関数の本体を指定せずに関数を宣言する

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またはusingステートメントです。

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

宣言と定義の違いを理解することが重要である大きな理由として、One Definition Ruleがあります。 C++標準のセクション3.2.1から:

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

163

宣言:「どこかに、fooがある」

定義: "...そしてここにあります!"

127
plinth

C++には興味深いEdgeのケースがあります(それらのいくつかは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++では、テンプレートを使用するときに、別のEdgeのケースがあります。

template <typename T>
struct X { 
  static int member; // declaration
};

template<typename T>
int X<T>::member; // definition

template<>
int X<bool>::member; // declaration!

最後の宣言はnot a定義でした。これはX<bool>の静的メンバーの明示的特殊化の宣言です。 「X<bool>::memberをインスタンス化することになるなら、プライマリテンプレートからメンバの定義をインスタンス化しないで、他の場所にある定義を使用してください」とコンパイラに伝えます。それを定義するためには、初期化子を供給しなければなりません

template<>
int X<bool>::member = 1; // definition, belongs into a .cpp file.

宣言

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

定義

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

32
adatapost

C99規格から、6.7(5):

宣言は、一連の識別子の解釈と属性を指定します。識別子の 定義 は、その識別子の宣言であり、次のようになります。

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

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

宣言は 定義 であり、関数の本体を指定せずに関数を宣言する場合、extern指定子またはリンケージ指定、初期化子も関数本体も含まない場合、クラス宣言内で静的データメンバを宣言します。それはクラス名宣言、またはtypedef宣言、using宣言、またはusingディレクティブです。

それからいくつかの例があります。

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

21
Steve Jessop

Wiki.answers.comから:

宣言とは、型、サイズ、および関数宣言の場合はプログラム内の任意の変数のパラメータの型とサイズ、あるいはユーザー定義の型または関数についてコンパイラに指示することを意味します。 いいえ 宣言は、変数のためにメモリ内に確保されます。しかし、コンパイラは、このタイプの変数が作成された場合にどの程度のスペースを確保するかを知っています。

たとえば、次はすべて宣言です。

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; 

回答 を参照してください。

15
Marcin Gil

C++ 11アップデート

C++ 11に関連した答えは見当たらないので、これは1つです。

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

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

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

  • 関数宣言 - add int add(int x, int y);
  • 宣言を含む外部指定子またはリンケージ指定子 - extern int a;またはextern "C" { ... };
  • クラス内の静的データメンバ - x class C { static int x; };
  • クラス/構造体宣言 - struct Point;
  • typedef宣言 - typedef int Int;
  • 宣言を使用して - using std::cout;
  • usingディレクティブ - 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
12
legends2k

宣言:

int a; // this declares the variable 'a' which is of type 'int'

したがって、宣言は変数を型に関連付けます。

以下は宣言の例です。

int a;
float b;
double c;

関数宣言:

int fun(int a,int b); 

関数の終わりにあるセミコロンに注意してください。それが宣言でしかないと言っています。コンパイラは、プログラムのどこかでそのプロトタイプでその関数が defined になることを知っています。コンパイラが関数呼び出しを受けた場合

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

今変数で。

int a; //declaration
a=10; //definition 

宣言と定義は、このように単一のステートメントにまとめられることがあります。

int a=10;
4
Sridharan

名詞を理解するために、まず動詞に注目しましょう。

宣言 - 公式に発表する。宣言する

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

ですから、何かを宣言するときには、 それを と言うだけです。

// declaration
int sum(int, int);

この行 は、 を宣言し、sumという2つの引数を取り、intを返すintというC関数です。しかし、まだ使えません。

を実際にどのように機能させるか を指定すると、それが定義になります。

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

経験則:

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

  • 定義 変数を既存にするためのメモリを予約します。これは最初のアクセスの前に一度だけ起きなければなりません。

4
bjhend

定義とは実際の関数が書かれていることを意味し、宣言とは例えば.

void  myfunction(); //this is simple declaration

そして

void myfunction()
{
 some statement;    
}

これが関数myfunctionの定義です

4
user565367

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

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 <[email protected]>
def=5;                     |  movb    $0x5,-0x45(%rbp)

宣言には同等の命令がありません。実行するものがないからです。

さらに、宣言はコンパイラに変数の有効範囲を指示します。

宣言は、変数の正しい使用方法および特定の変数に属するメモリの長さを確認するためにコンパイラによって使用される情報であると言えます。

3
princio

ここで同じような答えを見つける: Cでの技術面接の質問

宣言 は、プログラムに名前を付けます。 定義 は、プログラム内のエンティティ(例えば、タイプ、インスタンス、および機能)の一意の説明を提供する。宣言は与えられたスコープ内で繰り返すことができ、それは与えられたスコープ内に名前を導入します。

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

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

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

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

宣言は、記憶域が割り当てられていない識別子であり、定義が宣言された識別子から実際に記憶域を割り当てているという、最も一般的な用語で言えるでしょうか。

興味深い考え - テンプレートは、クラスまたは関数が型情報とリンクされるまで記憶域を割り当てることができません。それで、テンプレート識別子は宣言か定義か?ストレージが割り当てられていないので宣言であるべきです、そしてあなたは単にテンプレートクラスや関数の 'プロトタイプ'です。

2
user154171

宣言とは、変数に名前と型を付けることです(変数宣言の場合)。例:

 int i;  

または、本体なしで関数に名前、戻り型、およびパラメータ型を指定する(関数宣言の場合)

例えば:

int max(int, int);

定義とは、変数に値を代入することを意味します(変数定義の場合)。例えば:

i = 20;

あるいは、関数(body)を関数に提供/追加することを関数定義と呼びます。

例えば:

 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と関数max()を定義して宣言します。

1
Puneet Purohit

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

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

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

これは本当に安っぽいように思えるでしょうが、それは私が言葉を頭の中でまっすぐに保つことができた最も良い方法です:

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

定義:辞書を描く、あなたはFooとそれが実際に何を意味するのか探しています。

1
It'sPete

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

Cでは、宣言は単に関数または変数が存在するという情報を提供し、その型を示します。関数宣言の場合は、その引数の型に関する情報も提供されます。宣言の目的は、宣言された変数および関数への参照をコンパイラが正しく処理できるようにすることです。一方、定義は実際には変数のために記憶域を割り当てたり、関数が何をするのかを表します。

1
LinuxBabe

実行可能ファイル生成の段階:

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

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

翻訳者は次のことを確認してください:何が何ですか?は宣言を意味します

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

リンカーは次のことを確認してください:where is what what?は定義を意味します

0
Jeet Parikh

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

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

...

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

int sp;
double val[MAXVAL]

すべての関数の外に現れ、それらはdefine外部変数spおよびvalであり、ストレージを確保し、そのソースファイルの残りの宣言としても機能します。 。

一方、線

extern int sp;
extern double val[];

宣言spintであり、valdouble配列であるソースファイルの残りの部分(サイズは他で決定されます) 、ただし、変数を作成したり、変数用のストレージを予約したりしません。

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

...

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

0
Brad Solomon

私のお気に入りの例は "int Num = 5"です。ここであなたの変数は1. intとして定義されています我々

  • オブジェクトの型を定義します。これは、組み込み型、クラス、または構造体です。
  • オブジェクトの名前を宣言します。変数、機能などを含む名前の付いたものはすべて宣言されています。

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

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

プログラミングを学ぶとき、これら2つの用語はしばしば同時に混同されるので、混同されることがよくあります。

0
Jason K.

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

0
achoora