宣言は、識別子を紹介し、そのタイプを記述し、それはタイプ、オブジェクト、または関数です。宣言は、コンパイラがその識別子への参照を受け入れるために必要なものです。これらは宣言です:
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回だけ定義する必要があります。どこかで宣言および参照されているものを定義するのを忘れた場合、リンカは参照をリンクする対象を認識せず、シンボルの欠落について文句を言います。あなたが複数回何かを定義した場合、リンカは知らないこれへのリンク参照の定義の重複シンボルについて文句を言います。
C ++でのクラス宣言とクラス定義の違いについての議論が(他の質問への回答とコメントで)出続けているので、ここにC ++標準からの引用を貼り付けます。
3.1 / 2で、C ++ 03は次のように述べています。
[...]がクラス名宣言[...]でない限り、宣言は定義です。
次に、3.1 / 3にいくつかの例を示します。それらの中で:
[例:[...] struct 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
}
...またはであるtypedef
かusing
の文を。
typedef long LONG_32; // declares LONG_32
using namespace std; // declares std
ここで、宣言と定義の違いを理解することが重要である大きな理由があります。それは、単一定義規則です。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)から:
宣言は、一連の識別子の解釈と属性を指定します。定義識別子は、その識別子ことの宣言です。
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;
Answersを参照してください。
C ++ 11に関連する答えが見当たらないので、ここに1つあります。
a / nを宣言しない限り、宣言は定義です。
enum X : int;
template<typename T> class MyArray;
int 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 int a;
またはextern "C" { ... };
class C { static int x; };
struct Point;
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);
}
名詞を理解するために、最初に動詞に焦点を当てましょう。
宣言-公式に発表する。宣言する
定義-(誰かまたは何か)を明確かつ完全に表示または説明する
したがって、何かを宣言するときは、それが何であるかを伝えるだけです。
// declaration
int sum(int, int);
この行は、型の2つの引数を取り、を返すと呼ばれるC関数を宣言します。ただし、まだ使用できません。sum
int
int
それが実際にどのように機能するかを提供するとき、それがその定義です。
// definition
int sum(int x, int y)
{
return x + y;
}
定義は実際に書かれた関数を意味し、宣言は単純な宣言関数を意味します。
void myfunction(); //this is simple declaration
そして
void myfunction()
{
some statement;
}
これは関数myfunctionの定義です
経験則:
宣言は、メモリ内の変数のデータをどのように解釈するかをコンパイラに指示します。これはすべてのアクセスに必要です。
定義は、変数が既存にするためにメモリを予約します。これは、最初のアクセスの前に1回だけ発生する必要があります。
宣言と定義の違いを理解するには、アセンブリコードを確認する必要があります。
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)
宣言は実行されるものではないため、同等の命令はありません。
さらに、宣言はコンパイラに変数のスコープを通知します。
宣言は、変数の正しい使用法を確立するためにコンパイラーが使用する情報であり、一部のメモリーが特定の変数に属する期間であると言えます。
可能な限り最も一般的な用語で、宣言はストレージが割り当てられていない識別子であり、定義は宣言された識別子から実際にストレージを割り当てていると言えませんか?
興味深い考えの1つは、クラスまたは関数が型情報にリンクされるまで、テンプレートはストレージを割り当てることができないということです。では、テンプレート識別子は宣言または定義ですか?ストレージが割り当てられておらず、テンプレートクラスまたは関数を単に「プロトタイピング」しているため、これは宣言である必要があります。
ここで同様の回答を見つけてください:Cの技術面接の質問。
宣言は、プログラムに名前を提供します。定義は、プログラム内のエンティティ(例えばタイプ、インスタンス、および関数)の固有の説明を提供します。宣言は特定のスコープで繰り返すことができ、特定のスコープに名前を導入します。
以下の場合を除いて、宣言は定義です。
以下の場合を除いて、定義は宣言です。
これは本当に安っぽく聞こえるでしょうが、それは私が頭の中で用語をまっすぐに保つことができた最良の方法です:
宣言:トーマス・ジェファーソンがスピーチをしている写真...「私はここに、このFOOがこのソースコードに存在することを宣言します!!!」
定義:辞書を想像してください。あなたはFooとそれが実際に何を意味するのかを調べています。
宣言は、コンパイラーにシンボル名を提示します。定義は、シンボルにスペースを割り当てる宣言です。
int f(int x); // function declaration (I know f exists)
int f(int x) { return 2*x; } // declaration and definition
GNU Cライブラリのマニュアルによると(http://www.gnu.org/software/libc/manual/html_node/Header-Files.html)
Cでは、宣言は関数または変数が存在するという情報を提供し、そのタイプを提供するだけです。関数宣言の場合、その引数のタイプに関する情報も提供される場合があります。宣言の目的は、コンパイラが宣言された変数および関数への参照を正しく処理できるようにすることです。一方、定義は、実際には変数にストレージを割り当てるか、関数が何をするかを示します。
定義は他の場所にあり、ローカルコードファイル(ページ)で変数を宣言しているため、externストレージクラスを使用している場合、宣言と定義の概念は落とし穴を形成します。CとC ++の違いの1つは、Cでは、宣言は通常、関数またはコードページの先頭で行われることです。C ++では、そのようにはなりません。お好きな場所で宣言できます。
私のお気に入りの例は「intNum = 5」です。ここで、変数は1.intとして定義されます。2。Numとして宣言されます。3。値5でインスタンス化されます。私達
クラスまたは構造体を使用すると、後で使用するときにオブジェクトを定義する方法を変更できます。例えば
私たちがプログラミングを学ぶとき、私たちはしばしば両方を同時に行うので、これらの2つの用語はしばしば混同されます。
実行可能ファイル生成の段階:
(1)プリプロセッサ->(2)トランスレータ/コンパイラ->(3)リンカ
ステージ2(トランスレーター/コンパイラー)では、コード内の宣言ステートメントは、これらのものを将来使用することをコンパイラーに通知し、後で定義を見つけることができます。意味は次のとおりです。
翻訳者は次のことを確認します:何が何ですか?宣言を意味します
(3)ステージ(リンカー)は物事をバインドするための定義が必要です
リンカーは次のことを確認します:どこが何ですか?定義を意味します
K&R(第2版)全体に散りばめられた非常に明確な定義がいくつかあります。それらを1つの場所に配置し、1つとして読み取ると役立ちます。
「定義」とは、変数が作成またはストレージに割り当てられる場所を指します。「宣言」とは、変数の性質が記述されているが、ストレージが割り当てられていない場所を指します。[p。33]
..。
外部変数の宣言とその定義を区別することが重要です。宣言は、変数のプロパティ(主にその型)をアナウンスします。定義により、ストレージも確保されます。行の場合
int sp; double val[MAXVAL]
任意の関数の外に現れ、彼らが定義する外部変数を
sp
してval
、原因のストレージが確保されるべきではなく、また、そのソースファイルの残りの部分で宣言としての役割を果たす。一方、線
extern int sp; extern double val[];
宣言したソースファイルの残りのため
sp
でint
、それがval
あるdouble
(そのサイズは他の場所で決定される)の配列が、彼らは彼らのために変数や予備記憶を作成しないでください。ソースプログラムを構成するすべてのファイルの中で、外部変数の定義は1つだけでなければなりません。...配列サイズは定義で指定する必要がありますが、
extern
宣言ではオプションです。[pp。80-81]..。
宣言は、各識別子に与えられる解釈を指定します。識別子に関連付けられたストレージを必ずしも予約するわけではありません。ストレージを予約するという宣言は、定義と呼ばれます。[p。210]
宣言は、値またはオブジェクトを割り当てずに、プリミティブまたはオブジェクト参照変数またはメソッドが作成されたときです。int a; 最終的なinta;
定義は、値またはオブジェクトをそれぞれint a = 10に割り当てることを意味します。
初期化とは、それぞれの変数またはオブジェクトにメモリを割り当てることを意味します。
Reba McEntire が息子の Shelby Blackstock と共有しているクリスマスの伝統について学びましょう。
メーガン・マークルとマライア・キャリーが自然な髪の上でどのように結合したかについて、メーガンの「アーキタイプ」ポッドキャストのエピソードで学びましょう.
ハリー王子が家族、特にチャールズ王とウィリアム王子との関係について望んでいると主張したある情報源を発見してください。
ワイノナ・ジャッドが、母親のナオミ・ジャッドが亡くなってから初めての感謝祭のお祝いを主催しているときに、彼女が今では家長であることをどのように認識したかを学びましょう.
Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?
The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!
ランボルギーニの創設者であるフェルッチオランボルギーニが100歳になるのは毎日ではありません(そうです、彼は死んでいて、まだ死んでいると思います。
Appleが自動車分野に参入するという噂はかなり前から渦巻いており、AppleウォッチャーがSixtyEight Researchという会社がAppleの自動車研究開発のシェル会社である可能性が高いと判断したとき、その渦巻きは本当に渦巻いた。また、会社が購入した車は1台だけであることが知られており、その車はAppleが何を考えているかについての手がかりでいっぱいになる可能性があることも伝えています。
太陽系の外側にある架空の大きな物体である惑星Xの探索は、何十年にもわたって人間を魅了してきました。その検索の最新の章は、地球の10倍の大きさで、公転周期が15であるほど遠くにある惑星を指しています。
カムニュートンは昨日、簡単な265ヤードと3回のタッチダウンでファルコンズを引き裂き、別の素晴らしいゲームをしました。その日のハイライトは、上のタッチダウンスローでした。これは、視聴するたびにばかげているだけです。
ロシアのフィギュアスケーター、カミラ・バリエバが関与したドーピング事件が整理されているため、チームは2022年北京冬季オリンピックで獲得したメダルを待っています。
何千人ものAmazonの買い物客がMulberry Silk Pillowcaseを推奨しており、現在販売中. シルクの枕カバーにはいくつかの色があり、髪を柔らかく肌を透明に保ちます。Amazonで最大46%オフになっている間にシルクの枕カバーを購入してください
ラファイエット警察署は、「不審な男性が女性に近づいた」という複数の苦情を受けて、12 月にパデュー大学の教授の捜査を開始しました。
私たちの周りの世界と同じように、言語は常に変化しています。以前の時代では、言語の変化は数年または数十年にわたって発生していましたが、現在では数日または数時間で変化する可能性があります。
認知症を患っている 91 歳のアジア人女性が最近、47 番街のアウター サンセット地区でロメオ ロレンゾ パーハムに襲われました。伝えられるところによると、被害者はサンフランシスコの通りを歩いていたところ、容疑者に近づき、攻撃を受け、暴行を受けました。
“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.
人々にチャンスを与えることは、人生で少し遅すぎると私は信じています。寛大に。