C ++でexternを使用する場合


398

「Think in C ++」を読んでいて、extern宣言を紹介したところです。例えば:

extern int x;
extern float y;

意味(定義なしの宣言)は理解できたと思いますが、いつ役立つのか気になります。

誰かが例を提供できますか?


1
私はexternいくつかの場面で定義を提供しなければなりませんでした。Microsoftツールは、別のソースファイルのテーブルが定義されているだけの場合、欠落したシンボルのリンクエラーを生成しました。問題は、テーブルがconstあり、C ++コンパイラがそれをstatic変換単位に昇格させたことです。たとえば、ariatab.cppとを参照してくださいkalynatab.cpp
jww 2017

2
そして、C ++の質問に答えたように見えるのは彼だけなので、Nikの答えは正しいと思います。他のすべての人は、Cの質問を無視したようです。
jww 2017

回答:


519

これは、グローバル変数がある場合に役立ちます。ヘッダー内のグローバル変数の存在を宣言して、ヘッダーを含む各ソースファイルがそれを認識できるようにしますが、ソースファイルの1つで一度定義するだけで済みます。

明確にするために、using extern int x;は、int呼び出されたタイプのオブジェクトxどこかに存在することをコンパイラーに伝えます。それがどこにあるかを知るのはコンパイラの仕事ではなく、タイプと名前を知っている必要があるだけなので、それをどのように使用するかを知っています。すべてのソースファイルがコンパイルされると、リンカーはx、コンパイルされたソースファイルの1つで見つかった1つの定義へのすべての参照を解決します。それが機能するためには、x変数の定義に「外部リンケージ」と呼ばれるものが必要です。つまり、基本的には、関数の外(通常「ファイルスコープ」と呼ばれるもの)で、staticキーワードなしで宣言する必要があります。

ヘッダ:

#ifndef HEADER_H
#define HEADER_H

// any source file that includes this will be able to use "global_x"
extern int global_x;

void print_global_x();

#endif

ソース1:

#include "header.h"

// since global_x still needs to be defined somewhere,
// we define it (for example) in this source file
int global_x;

int main()
{
    //set global_x here:
    global_x = 5;

    print_global_x();
}

ソース2:

#include <iostream>
#include "header.h"

void print_global_x()
{
    //print global_x here:
    std::cout << global_x << std::endl;
}

15
ありがとうございました。したがって、externキーワードを使用せずにヘッダーファイルでグローバル変数を宣言した場合、ヘッダーを含むソースファイルはグローバル変数を認識しませんか?
Aslan986

23
ヘッダーでグローバル変数を宣言しないでください。2つのファイルに同じヘッダーファイルが含まれていると、リンクされません(リンカーは「シンボルの重複」に関するエラーを出力します)
kuba

63
@ Aslan986:いいえ、何か悪いことが起こります。ヘッダーを含む各ソースファイルには独自の変数があるため、各ソースファイルは個別にコンパイルされますが、2つのソースファイルが同じグローバル識別子を持っているため、リンカーは文句を言います。
dreamlax

7
「extern」という単語を使用しない場合は、変数が存在します。「extern」を使用すると、「このvarがどこかにある」ということになります。定義か宣言かわからないのは申し訳ありません。私はいつもこの2つについて混乱するからです。
クバ

3
@CCJ:インクルードガードは、それを含むソースファイルに対してのみ機能します。同じヘッダーが同じソースファイル内に2回含まれるのを停止します(他のヘッダーにも含まれる場合に備えて)。そのため、インクルードガードを使用しても、ヘッダーを含む各ソースファイルには独自の定義があります。
dreamlax

172

いくつかのモジュール間で変数を共有する場合に役立ちます。1つのモジュールで定義し、他のモジュールでexternを使用します。

例えば:

file1.cpp内:

int global_int = 1;

file2.cpp内:

extern int global_int;
//in some function
cout << "global_int = " << global_int;

39
この回答は、ヘッダーファイルを使用せず、少数のモジュール間で共有する場合にのみ役立つと明確に述べているため、承認された回答よりも正確です。大きなアプリケーションの場合は、たとえばConfigManagerクラスを使用することをお勧めします。
Zac

1
名前空間が含まglobal_intれている場合、グローバル名前空間にある場合、何か問題がありますか?私がそれを正しい名前空間セクションのfile2.cppで使用した場合、スコープを正しく設定する必要がありますか?ienamespace XYZ{ void foo(){ ::global_int++ } };
jxramos 2015

8
@Zac:一方、ヘッダーでグローバル変数を宣言しないことにより、実際にどこで定義されているかを判別するのがうっかり困難になります。通常、グローバル変数がで宣言されているabc.h場合、それがで定義される可能性が高くなりますabc.cpp。優れたIDEは常に役に立ちますが、よく整理されたコードは常により良いソリューションです。
dreamlax

externfile2.cppになくても、インクルードglobal_int後にアクセスできます。なぜそれが必要なのですか?
TomSawyer

62

それはすべてリンケージについてです。

以前の回答は、についての適切な説明を提供しましたextern

しかし、私は重要なポイントを追加したいと思います。

あなたは尋ねるexternC ++ではないにCや無応答の場合についての言及はありませんなぜ私は知りませんexternが付属していますconstC ++には。

C ++では、const変数にはデフォルトで内部リンケージがあります(Cとは異なります)。

したがって、このシナリオではリンクエラーが発生します

ソース1:

const int global = 255; //wrong way to make a definition of global const variable in C++

ソース2:

extern const int global; //declaration

次のようにする必要があります。

ソース1:

extern const int global = 255; //a definition of global const variable in C++

ソース2:

extern const int global; //declaration

2
定義部分に 'extern'を含めずにc ++で動作しているのになぜそれが間違っているのですか?
チーフシフター

1
VIsual StudioのVisual Microとのリンクエラーは発生しないようです。何が欠けていますか?
Craig.Fayed 2017

1
@ lartist93 @ C​​raig.Feiedもう一度確認する必要があると思います。コンパイラがリンクエラーを通知しない場合でも、両方のソースの両方のオブジェクトexternが定義なしで同じであることを確認できますか?あなたは、の値をプリントアウトすることにより、それを行うことができglobal、ソース2に
トレバー

3
確認は、MSVS 2018年がある場合はリンクエラーexternに省略されていますconst int global = 255;
2018

13

これは、グローバル変数が必要な場合に役立ちます。一部のソースファイルでグローバル変数を定義し、それらをヘッダーファイルでexternと宣言して、そのヘッダーファイルを含むすべてのファイルが同じグローバル変数を参照できるようにします。


とにかく、これは非常にOOPに聞こえません、それらをシングルトンクラスに入れます...またはローカル静的値を返す関数...
RzR
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.