外部リンクと内部リンク、およびそれらの違いを理解したいと思います。
また、の意味を知りたい
const
と宣言されていない限り、extern
変数はデフォルトで内部的にリンクします。
実装ファイル(.cpp
、.cxx
など)を作成すると、コンパイラーは翻訳単位を生成します。これは、実装ファイルのオブジェクトファイルと、その中の#include
dのすべてのヘッダーです。
内部リンケージは、すべてを指す翻訳単位の範囲内。
外部リンケージは、特定の翻訳単位を超えて存在するものを指します。つまり、プログラム全体からアクセス可能は、すべての翻訳単位(またはオブジェクトファイル)の組み合わせです。
dudewat saidexternalリンケージは、シンボル(関数またはグローバル変数)がプログラム全体でアクセス可能であり、internalリンケージは、1つの translation unit でのみアクセス可能であることを意味します。
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
を使用する代わりに、 anonymous namespaces を使用して、class
esを入れることもできます。匿名名前空間のリンケージはC++ 98とC++ 11の間で変更されましたが、主なことは、他の翻訳単位から到達できないことです。
namespace {
int i; // external linkage but unreachable from other translation units.
class invisible_to_others { };
}
次の例を検討してください。
void f(int i);
extern const int max = 10;
int n = 0;
int main()
{
int a;
//...
f(a);
//...
f(a);
//...
}
#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;
}
NB:キーワードstaticは二重の役割を果たします。グローバル変数の定義で使用する場合、内部リンケージを指定します。ローカル変数の定義で使用される場合、変数の有効期間が関数の期間ではなくプログラムの期間になることを指定します。
お役に立てば幸いです!
「C」で異なるスコープについて話しましょう
範囲:基本的に、どれくらいの時間、どこまで見ることができるかです。
ローカル変数:スコープは関数内のみです。 RAMのSTACK領域にあります。つまり、関数が呼び出されるたびに、関数の引数を含む、その関数の一部であるすべての変数が新しく作成され、コントロールが関数から出ると破棄されます。 (関数が戻るたびにスタックがフラッシュされるため)
静的変数:このスコープはファイル用です。ファイル内のすべての場所にアクセスできます
宣言されています。 RAMのDATAセグメントにあります。これはファイル内でのみアクセスできるため、内部リンケージです。どれか
他のファイルはこの変数を見ることができません。実際、STATICキーワードは、あるレベルのデータまたは機能を導入できる唯一の方法です
「C」に隠れています
グローバル変数:これの範囲はアプリケーション全体です。アプリケーションのどこからでもアクセスできます。グローバル変数はDATAセグメントにも存在します。これは、アプリケーション内のすべての場所にアクセスできるため、外部リンクです。
デフォルトでは、すべての機能はグローバルです。場合によっては、ファイル内の一部の関数を外部から隠す必要がある場合、静的キーワードを関数の前に付けることができます。 :-)
質問について話す前に、用語 translation unit 、 program およびC++の一部の 基本概念 (実際にはリンケージは一般にそれらの1つです)。 scope とは何かを知る必要もあります。
私はいくつかの重要なポイント、特にを強調します。以前の回答にないもの。
Linkageはnameのプロパティであり、宣言。異なる名前は同じentity(通常、オブジェクトまたは関数)を示すことができます。そのため、エンティティの特定の宣言から一意の名前によってのみ参照されることが確実でない限り、エンティティのlinkageについて話すことは通常ナンセンスです(通常ただし、1つの宣言)。
objectはエンティティですが、variableはエンティティではありません。変数のリンケージについては、実際には、指定されたエンティティ(特定の宣言によって導入される)の名前が関係します。名前のリンケージは、リンケージなし、内部リンケージ、または外部リンケージの3つのうちの1つです。
異なる翻訳単位は、ヘッダー/ソースファイル(はい、標準の表現)の包含によって同じ宣言を共有できます。そのため、異なる翻訳単位で同じ名前を参照できます。宣言された名前に外部リンケージがある場合、名前によって参照されるエンティティのIDも共有されます。宣言された名前に内部リンケージがある場合、異なる翻訳単位の同じ名前は異なるエンティティを示しますが、同じ翻訳単位の異なるスコープでエンティティを参照できます。名前にリンケージがない場合、他のスコープからエンティティを参照することはできません。
(おっと...私が入力したのは、やや繰り返しているだけだとわかった 標準の言い回し ...)
言語仕様でカバーされていない他の混乱するポイントもいくつかあります。
__attribute__
または__declspec
などの一部の拡張機能を含む)またはコンパイラオプションから内部的にそのイメージでのみ共有指定でき、イメージはプログラム全体またはオブジェクトファイルではありません翻訳ユニットから翻訳されるため、標準的な概念では正確に説明できません。シンボルはC++の規範的な用語ではないため、方言の関連する拡張が広く採用されている場合でも、実装の詳細にすぎません。名前空間スコープconst
変数のリンクルール は特別なものです(特に、識別子のリンケージの概念を持つC言語のファイルスコープで宣言されたconst
オブジェクトとは異なります)。 ODR はC++によって実施されるため、 inline
関数を除くプログラム全体で発生した同じ変数または関数の定義を1つだけ保持することが重要です 。 const
のような特別なルールがない場合、複数の翻訳単位に含まれる(または1つの翻訳単位に含まれる)ヘッダーまたはソースファイル(多くの場合「ヘッダーファイル」)にイニシャライザー(= xxx
など)を持つconst
変数の最も単純な宣言プログラム内でODRに違反することはめったにありませんが、これによりconst
変数を一部のオブジェクトのようなマクロの置換として使用できなくなります。
C++の内部および外部リンク は、明確で簡潔な説明を与えると思います。
変換単位は、実装(.c/.cpp)ファイルとそれに含まれるすべてのヘッダー(.h/.hpp)ファイルを指します。そのような翻訳単位内のオブジェクトまたは関数が内部リンケージを持っている場合、その特定のシンボルはその翻訳単位内のリンカーにのみ表示されます。オブジェクトまたは関数に外部リンケージがある場合、リンカは他の変換単位を処理するときにそれを確認することもできます。 staticキーワードは、グローバル名前空間で使用されると、シンボルに内部リンクを強制します。 externキーワードは、外部リンケージを持つシンボルをもたらします。
コンパイラは、シンボルのリンケージをデフォルトで次のようにします。
非constグローバル変数にはデフォルトで外部リンケージがあります
Constグローバル変数には、デフォルトで内部リンケージがあります
関数にはデフォルトで外部リンケージがあります
リンケージは、同じ名前の識別子が同じオブジェクト、関数、または他のエンティティを参照するかどうかを決定します(それらの識別子が異なる翻訳単位に表示されている場合でも)。識別子のリンケージは、それが宣言された方法に依存します。リンケージには3つのタイプがあります。
C++のみ:C++コードフラグメントと非C++コードフラグメントの間にリンケージを作成することもできます。これは言語リンケージと呼ばれます。
ソース: IBM Program Linkage
基本的に
extern linkage
変数はすべてのファイルに表示されますinternal linkage
変数は単一のファイルに表示されます。説明:const変数は、externと宣言されていない限り、デフォルトで内部的にリンクします
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++の場合
クラスまたは関数内にネストされていないファイルスコープの変数は、プログラム内のすべての翻訳単位で表示されます。これは、外部リンケージと呼ばれます。これは、リンク時に、その変換ユニットの外部のどこからでもリンカーに名前が見えるためです。
グローバル変数と通常の関数には外部リンケージがあります。
静的ファイルスコープのオブジェクト名または関数名は翻訳単位に対してローカルです。それはInternal Linkageと呼ばれます
リンケージは、リンク/ロード時にアドレスを持つ要素のみを参照します。したがって、クラス宣言とローカル変数にはリンケージがありません。