1. ホーム
  2. C++

extern const の使用法

2022-03-16 18:02:26

質問1

1.cpp

extern const int i; //const int i = 1;
const int i = 1; //extern const int i;
int main(){return 0;}

2.cpp

extern const int i = 2;

コメントの順番通りならリンクが通るのに、これが通らないのはどう説明するのでしょうか?

質問2

C++で、グローバルシンボル定数を定義しなさい。



a.cpp で extern const double pi=3.14 を定義する。



b.ppでextern const double piを宣言する。



はコンパイルで実行できます。



a.cpp で const double pi=3.14 を定義する。



b.ppでextern const double piを宣言する。



コンパイルに失敗しました(a.cpp の pi 定数は extern キーワードで見つからず、スコープは a.cpp ファイルドメイン内のみです)。

この2つの問題については、明確にしなければならない概念がいくつかあります。

  1. constオブジェクトはファイルローカル変数です。つまり、他のファイルはこのファイルのConst変数にリンクすることができません。

  2. constの前にexternを付けると、このconstオブジェクトは他のファイルからリンクできることを意味します。

  3. const変数をexternで初期化するのではなく、宣言を取得する場合、コンパイラはまずこのexternの前にあるオブジェクトの初期化宣言を探すことを選択します。これは、constのスコープが本質的にファイルスコープであるため、理解しやすいと思います。もし、自分自身のexternの前に見つからなかったら(コンパイラはコードをトップダウンでコンパイルするので、その後に何が来るかはわかりません)、そのオブジェクトの初期化にexternを使っている他の場所がないか、外を探します(他の場所でconst定数を初期化するには、それらすべてがexternを持っていなければなりません)。もしあれば、コンパイルは成功します。なければ、リンクエラーが報告されます。

課題1の分析。

上記の3つのポイントに目を通してください。あなたのコードを解釈してみましょう。1.cppで最初にextern const int iとすると、上記の3番目のポイントによると、まずiの初期化がないうちに自分自身を探しますが、明らかに何も見つかりません。そこで、ファイルの外に出て、リンクのプレースホルダーを探すと、2.cppにそのような定義が確かにあることがわかります。つまり、const i が見つかり、初期化されたのです。そしてその次の文はiの定義なので、コンパイルエラーではなくリンクエラーに違いありません:fatal error LNK1169: one or more multiply defined symbols found.

では、なぜその逆が起きないのでしょうか?最初の文はローカル変数iを定義して初期化しています。2番目の文はその変数をexternしています。extern変数がconstオブジェクトの場合、今度は自分のファイルの中を探し、見つかったらどこにもリンクしない。constはもともとファイルのドメインだからです。そうすると当然リンクエラーは発生しません。その結果をmain関数でiを出力して実行してみると、iの値が2ではなく1であることがわかります。

問題2解析。

定数変数は定義時に初期化する必要があるので、extern const double pi=3.14 in a.cpp; extern const double pi in b.pp; がコンパイル時に実行できるようになります。なぜなら,コンパイルシステムはa.cppでグローバル定数変数を見つけたとき,それがpiであることを知っており,それが切り替わったとき,const double pi=3.14 in a.cpp; extern const double pi in b.pp; を定義すると,コンパイルシステムはa.cppを問題なくコンパイルしますが,それがb.に来ると,コンパイルシステムはpiを初期化します. cppでは、外部定数が初期化されていないことがわかり(a.cppのconst定数はexternキーワードを持っていない)、定数は宣言された後に定義できないので、コンパイルシステムはその定義が見つからないと思い、エラーになります。