回答:
あなたは(実装ファイルを書くとき.cpp
、.cxx
など)あなたのコンパイラが生成翻訳単位を。これは、実装のソースファイルと、その中にあるすべてのヘッダーです#include
。
内部リンケージとは、翻訳単位の範囲内にあるすべてのものを指します。
外部リンケージは、特定の翻訳単位を超えて存在するものを指します。つまり、すべての翻訳単位(またはオブジェクトファイル)の組み合わせであるプログラム全体からアクセスできます。
const
変数のルール(およびその目的)に関する質問はここでは完全に見逃されているため、この回答は不完全です。
以下のようdudewatは言っ 外部リンケージは、シンボル(関数やグローバル変数)は、プログラム全体を通してアクセス可能であることを意味し、内部には1つのでのみアクセス可能だとリンケージ手段翻訳単位。
キーワードextern
とを使用して、シンボルのリンクを明示的に制御できstatic
ます。リンケージが指定されていない場合、デフォルトのリンケージはextern
非const
シンボル用とstatic
(内部)const
シンボル用です。
// in namespace or global scope
int i; // extern by default
const int ci; // static by default
extern const int eci; // explicitly extern
static int si; // explicitly static
// the same goes for functions (but there are no const functions)
int foo(); // extern by default
static int bar(); // explicitly static
static
内部リンケージに使用するのではなく、esを入れることのできる匿名の名前空間を使用することをお勧めしますclass
。匿名名前空間のリンケージはC ++ 98とC ++ 11の間で変更されましたが、主なことは、それらが他の翻訳単位から到達できないことです。
namespace {
int i; // external linkage but unreachable from other translation units.
class invisible_to_others { };
}
extern
、他のファイルで宣言ます。static
。そのような変数は内部リンケージを持っていると言われています。次の例を検討してください。
void f(int i);
extern const int max = 10;
int n = 0;
int main()
{
int a;
//...
f(a);
//...
f(a);
//...
}
f
宣言f
します(デフォルト)。その定義は、後でこのファイルまたは他の翻訳単位(下記に示す)で提供する必要があります。max
整数定数として定義されます。定数のデフォルトのリンケージはinternalです。そのリンケージは、キーワードを使用して外部に変更されextern
ます。だから今max
、他のファイルでアクセスできるようになりました。n
整数変数として定義されます。関数本体の外部で定義された変数のデフォルトのリンケージは外部です。#include <iostream>
using namespace std;
extern const int max;
extern int n;
static float z = 0.0;
void f(int i)
{
static int nCall = 0;
int a;
//...
nCall++;
n++;
//...
a = max * z;
//...
cout << "f() called " << nCall << " times." << endl;
}
max
外部リンケージがあると宣言されています。max
(外部リンケージを使用する)の一致する定義は、いくつかのファイルに存在する必要があります。(1.cppと同様)n
外部リンケージがあると宣言されています。z
されている定義されたグローバル変数として内部リンケージ。nCall
指定nCall
しますf()
。デフォルトの自動ストレージクラスを持つローカル変数とは異なりnCall
、は、プログラムの起動時に1回だけ初期化され、の呼び出しごとに1回は初期化されませんf()
。ストレージクラス指定子static
は、そのスコープではなく、ローカル変数の有効期間に影響します。注意:キーワードstatic
は2つの役割を果たします。グローバル変数の定義で使用する場合は、内部リンケージを指定します。ローカル変数の定義で使用される場合、変数の存続期間が関数の継続時間ではなくプログラムの継続時間になることを指定します。
お役に立てば幸いです。
static
遅延単一初期化が可能になります(グローバルなオブジェクトが必要だが、グローバルな構築順序の問題のためにいつ構築されるかを制御する必要があり、動的に割り当てることができない場合に役立ちます)使用new
含意することによって、これは)、C ++を使用して組み込みシステム上の問題は主に、より詳細な初期化スキームは、当該オブジェクトの必要なものを超えてもよいです。
「C」のさまざまなスコープについて話しましょう
スコープ:基本的に、私は何かをどのくらい遠くまで見ることができますか。
ローカル変数:スコープは関数内のみです。RAMのスタック領域にあります。つまり、関数が呼び出されるたびに、関数の引数を含め、その関数の一部であるすべての変数が新たに作成され、コントロールが関数から出ると破棄されます。(関数が戻るたびにスタックがフラッシュされるため)
静的変数:このスコープはファイル用です。
宣言されているファイルのどこからでもアクセスできます。RAMのDATAセグメントに存在します。これはファイル内でしかアクセスできないため、内部リンクです。任意の
他のファイルには、この変数を参照することはできません。実際、STATICキーワードは、
「C」にデータや関数の非表示を導入できる唯一の方法です。
グローバル変数:このスコープはアプリケーション全体です。アプリケーションのどこからでもアクセスできます。グローバル変数もDATAセグメントにあります。アプリケーション内のどこからでもアクセスできるため、外部リンク
デフォルトでは、すべての関数がグローバルです。ファイル内の一部の関数を外部から非表示にする必要がある場合は、関数の前にstaticキーワードを付けることができます。:-)
質問について話す前に、「翻訳単位」、「プログラム」、およびC ++のいくつかの基本概念(実際には、リンケージは一般にその1つです)を正確に理解することをお勧めします。また、スコープとは何かを知る必要があります。
特にいくつかの重要なポイントを強調します。以前の回答で不足しているもの。
リンケージは名前のプロパティであり、宣言によって導入されます。異なる名前が同じエンティティ(通常はオブジェクトまたは関数)を表す場合があります。リンケージについて話します、エンティティが特定の宣言(通常は1つの宣言)からの一意の名前によってのみ参照されることが確実でない限り、エンティティのは通常ナンセンスです。
オブジェクトはエンティティですが、変数であることに注意してくださいははないことに。変数のリンケージについて説明するとき、実際には、(特定の宣言によって導入される)指定されたエンティティーの名前が関係します。名前のリンケージは、リンケージなし、内部リンケージ、または外部リンケージの3つのうちの1つです。
異なる翻訳単位は、ヘッダー/ソースファイル(はい、それは標準の表現です)を含めることで同じ宣言を共有できます。そのため、同じ名前を異なる翻訳単位で参照できます。宣言された名前に外部リンケージがある場合、その名前で参照されるエンティティのIDも共有されます。宣言された名前に内部リンケージがある場合、異なる翻訳単位の同じ名前は異なるエンティティを示しますが、同じ翻訳単位の異なるスコープのエンティティを参照できます。名前にリンケージがない場合、エンティティを他のスコープから参照することはできません。
(おっと...私が入力したのは、標準的な言葉遣いを幾分か繰り返すだけだった...)
言語仕様ではカバーされていない他のいくつかの混乱する点もあります。
__attribute__
、または__declspec
)またはコンパイラオプション。画像はプログラム全体でも、翻訳単位から翻訳されたオブジェクトファイルでもないため、標準の概念では正確に説明できません。シンボルはC ++では規範的な用語ではないため、関連する方言の拡張が広く採用されている場合でも、これは実装の詳細にすぎません。名前空間スコープconst
変数のリンケージルールは特別なものです(const
C言語のファイルスコープで宣言されているオブジェクトとは異なり、識別子のリンケージの概念もあります)。以来ODRは、 C ++によって強制され、同じ変数や関数の1以下の定義は除いプログラム全体で発生していない維持することが重要であるinline
機能。そのような特別な規則がない場合、複数の翻訳単位に含まれる(または複数の翻訳単位に複数回含まれる)ヘッダーまたはソースファイル(多くの場合「ヘッダーファイル」)に初期化子(例const
:)を含むconst
変数の最も単純な宣言= xxx
、まれですが)プログラムでODRに違反しますconst
一部のオブジェクトのようなマクロの置換として変数は不可能です。
C ++の内部と外部のリンケージが明確で簡潔な説明を与えると思います:
翻訳単位とは、実装(.c / .cpp)ファイルと、それに含まれるすべてのヘッダー(.h / .hpp)ファイルを指します。そのような翻訳単位内のオブジェクトまたは関数に内部リンケージがある場合、その特定のシンボルは、その翻訳単位内のリンカーにのみ表示されます。オブジェクトまたは関数に外部リンケージがある場合、リンカは他の翻訳単位を処理するときにもそれを見ることができます。staticキーワードをグローバル名前空間で使用すると、シンボルに内部リンケージが強制されます。externキーワードは、外部リンケージを持つシンボルになります。
コンパイラーは、次のようなシンボルのリンケージをデフォルト設定します。
非constグローバル変数にはデフォルトで外部リンケージがあります
Constグローバル変数にはデフォルトで内部リンケージがあります
関数にはデフォルトで外部リンケージがあります
リンケージは、同じ名前の識別子が同じオブジェクト、関数、または他のエンティティを参照しているかどうかを判断します。これらの識別子が異なる翻訳単位で表示されている場合でも同じです。識別子のリンケージは、それがどのように宣言されたかによって異なります。リンケージには3つのタイプがあります。
C ++のみ:C ++コードフラグメントと非C ++コードフラグメントの間にリンケージを作成することもできます。これは言語リンケージと呼ばれます。
基本的に
extern linkage
変数はすべてのファイルに表示されますinternal linkage
変数は単一のファイルに表示されます。説明:externとして宣言されていない限り、const変数はデフォルトで内部的にリンクします
external linkage
const
グローバル変数はinternal linkage
extern const
なグローバル変数はexternal linkage
C ++でのリンケージに関するかなり良い資料
http://www.goldsborough.me/c/c++/linker/2016/03/30/19-34-25-internal_and_external_linkage_in_c++/
C ++の場合
ファイルスコープにあり、クラスまたは関数内にネストされていない変数は、プログラムのすべての変換単位で表示されます。これは外部リンケージと呼ばれます。リンク時に、その名前はその翻訳単位の外部にあるリンカから見えるためです。
グローバル変数と通常の関数には外部リンケージがあります。
ファイルスコープの静的オブジェクトまたは関数名は、変換単位に対してローカルです。それは内部リンケージと呼ばれています
リンケージは、リンク/ロード時にアドレスを持つ要素のみを参照します。したがって、クラス宣言とローカル変数にはリンケージがありません。