...
#include "test1.h"
int main(..)
{
count << aaa <<endl;
}
aaa
で定義されておりtest1.h
、 extern キーワードを使用していませんが、参照できますaaa
。
だから私はextern
本当に必要だと思いますか?
extern
その用途があります。しかし、それは主に、嫌われている「グローバル変数」を含みます。背後にある主なアイデアextern
は、外部リンクで物事を宣言することです。そのため、それはの反対のようなものですstatic
。ただし、多くの場合、外部リンケージはデフォルトのリンケージであるため、そのような場合は必要ありませんextern
。別の用途extern
は次のとおりです。定義を宣言に変えることができます。例:
extern int i; // Declaration of i with external linkage
// (only tells the compiler about the existence of i)
int i; // Definition of i with external linkage
// (actually reserves memory, should not be in a header file)
const int f = 3; // Definition of f with internal linkage (due to const)
// (This applies to C++ only, not C. In C f would have
// external linkage.) In C++ it's perfectly fine to put
// somethibng like this into a header file.
extern const int g; // Declaration of g with external linkage
// could be placed into a header file
extern const int g = 3; // Definition of g with external linkage
// Not supposed to be in a header file
static int t; // Definition of t with internal linkage.
// may appear anywhere. Every translation unit that
// has a line like this has its very own t object.
ほら、それはかなり複雑です。2つの直交する概念があります:リンケージ(外部対内部)と宣言対定義の問題。extern
キーワードは両方に影響を与える可能性があります。リンケージに関しては、の反対ですstatic
。しかし、の意味static
もオーバーロードされており、コンテキストに応じて、リンケージを制御するかどうかを決定します。それが行う他のことは、オブジェクトの寿命(「静的寿命」)を制御することです。しかし、グローバルスコープでは、すべての変数にはすでに静的な存続期間があり、リンケージを制御するためにキーワードをリサイクルするのは良い考えだと考える人もいます(これは私が推測しているだけです)。
リンケージは基本的に、「名前空間スコープ」で宣言/定義されたオブジェクトまたは関数のプロパティです。内部リンケージがある場合、他の翻訳ユニットから名前で直接アクセスすることはできません。外部リンケージがある場合は、すべての変換単位にわたって1つの定義のみが存在する必要があります(例外を除き、one-definition-ruleを参照してください)。
データを整理する最善の方法は、次の 2 つの簡単なルールに従うことです。
宣言とは、何かが存在することをコンパイラーに通知することを意味しますが、それらにストレージを割り当てません。これにはtypedef
、struct
などextern
が含まれます。
定義とは、通常、「スペースを割り当てる」などを意味int
します。
次のような行がある場合:
int aaa;
ヘッダー ファイルでは、すべてのコンパイル ユニット (基本的にはコンパイラへの入力ストリームとして定義されます。C ファイルと で取り込まれるすべてのものを#include
再帰的に定義します) は、独自のコピーを取得します。同じシンボルが定義されている 2 つのオブジェクト ファイルを一緒にリンクすると、問題が発生します ( のような特定の限られた状況を除くconst
)。
aaa
これを行うためのより良い方法は、C ファイルの 1 つでその変数を定義してから、次のようにすることです。
extern int aaa;
ヘッダーファイルで。
ヘッダー ファイルが 1 つの C ファイルにのみ含まれている場合、これは問題ではないことに注意してください。しかし、その場合、おそらくヘッダー ファイルすらありません。私の意見では、ヘッダー ファイルはコンパイル ユニット間で共有するためだけのものです。
test1.h に aaa の定義があり、ヘッダー ファイルを複数の翻訳単位に含めたい場合、aaa が定数でない限り、複数の定義エラーが発生します。cpp ファイルで aaa を定義し、他のファイルにヘッダーとして追加できるヘッダー ファイルに extern 定義を追加することをお勧めします。
ヘッダー ファイルに変数と定数を含めるための経験則
extern int a ;//Data declarations
const float pi = 3.141593 ;//Constant definitions
定数には c++ の内部リンケージがあるため、翻訳単位で定義されている定数は他の翻訳単位からは見えませんが、外部リンケージを持つ変数の場合はそうではありません。つまり、他の翻訳単位から見えます。他の翻訳単位で共有されている変数の定義をヘッダーに入れると、変数の多重定義が発生し、多重定義エラーが発生します。
その場合extern
は必要ありません。Extern は、シンボルが別のコンパイル単位で宣言されている場合に必要です。
前処理ディレクティブを使用する#include
と、インクルード ファイルがディレクティブの代わりにコピーされます。この場合extern
、コンパイラはすでに知っているので必要ありませんaaa
。
aaa が別のコンパイル単位で定義されていない場合、extern は必要ありません。