外部リンケージと内部リンケージとその違いを理解したい。
の意味も知りたい
const
変数は、特に宣言されていない限り、デフォルトで内部的にリンクされますextern
。
実装ファイル ( .cpp
、.cxx
など) を作成すると、コンパイラによって翻訳単位が生成されます。これは、実装のソース ファイルと、それに含まれるすべてのヘッダーです#include
。
内部リンケージは、翻訳単位の範囲内でのみすべてを参照します。
外部リンケージとは、特定の翻訳単位を超えて存在するものを指します。つまり、すべての翻訳単位 (またはオブジェクト ファイル) の組み合わせであるプログラム全体からアクセスできます。
dudewatが言ったよう に、外部リンケージはシンボル(関数またはグローバル変数)がプログラム全体でアクセスできることを意味し、内部リンケージは1つの翻訳単位でのみアクセスできることを意味します。
extern
およびstatic
キーワードを使用して、シンボルのリンケージを明示的に制御できます。リンケージが指定されていない場合、デフォルトのリンケージは、非シンボルの場合はextern
(外部リンケージ) であり、シンボルの場合は(内部リンケージ) です。const
static
const
// In namespace scope 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 f(); // extern by default
static int sf(); // explicitly static
static
(内部リンケージ)を使用する代わりに、esを配置できる匿名の名前空間を使用する方がよいことに注意してください。それらはリンケージclass
を許可しますが、匿名の名前空間は他の翻訳単位から到達できないため、効果的にリンケージを行います。extern
static
namespace {
int i; // extern by default but unreachable from other translation units
class C; // extern by default but unreachable from other translation units
}
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
整数変数として定義されます。関数本体の外側で定義された変数のデフォルトのリンケージはexternalです。#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
指定します。デフォルトの auto ストレージ クラスのローカル変数とは異なり、はプログラムの開始時に 1 回だけ初期化され、 の呼び出しごとに 1 回ではありません。ストレージ クラス指定子は、スコープではなく、ローカル変数の有効期間に影響します。nCall
f()
nCall
f()
static
注意:キーワードstatic
には 2 つの役割があります。グローバル変数の定義で使用すると、内部リンケージを指定します。ローカル変数の定義で使用すると、変数の有効期間が関数の期間ではなく、プログラムの期間になることを指定します。
それが役立つことを願っています!
'C'のさまざまなスコープについて話しましょう
範囲:基本的に、私は何かをどれくらいの時間、どこまで見ることができるかです。
ローカル変数:スコープは関数内にのみあります。RAMのスタック領域にあります。つまり、関数が呼び出されるたびに、関数の引数を含むその関数の一部であるすべての変数が新たに作成され、コントロールが関数から外れると破棄されます。(関数が戻るたびにスタックがフラッシュされるため)
静的変数:このスコープはファイル用です。
宣言されているファイルのどこからでもアクセスできます。RAMのDATAセグメントにあります。これはファイル内でのみアクセスできるため、内部リンケージになります。他
のファイルはこの変数を見ることができません。
実際、STATICキーワードは、 「C」に隠れているあるレベルのデータまたは関数を導入できる唯一の方法です。
グローバル変数:これの範囲はアプリケーション全体です。アプリケーションのどこからでもアクセスできます。グローバル変数もDATAセグメントに存在します。これは、アプリケーションのどこからでもアクセスできるため、外部リンケージにアクセスできるためです。
デフォルトでは、すべての関数はグローバルです。ファイル内の一部の関数を外部から非表示にする必要がある場合は、関数の前にstaticキーワードを付けることができます。:-)
質問について話す前に、翻訳単位、プログラム、および C++ のいくつかの基本的な概念(実際、リンケージは一般的にそれらの 1 つです) という用語を正確に知っておくことをお勧めします。また、スコープとは何かを知る必要があります。
特にいくつかの重要なポイントを強調します。以前の回答に欠けているもの。
リンケージは、宣言によって導入される名前のプロパティです。異なる名前で同じエンティティ(通常はオブジェクトまたは関数) を表すことができます。そのため、エンティティがいくつかの特定の宣言 (通常は 1 つの宣言) からの一意の名前によってのみ参照されることが確実でない限り、エンティティのリンケージについて話すことは通常ナンセンスです。
オブジェクトはエンティティですが、変数はエンティティではないことに注意してください。変数のリンケージについて話している間、実際には、示されたエンティティ (特定の宣言によって導入される) の名前が関係しています。名前のリンケージは、リンケージなし、内部リンケージ、または外部リンケージの 3 つのうちの 1 つにあります。
異なる翻訳単位は、ヘッダー/ソース ファイル (はい、標準の文言です) を含めることで同じ宣言を共有できます。したがって、異なる翻訳単位で同じ名前を参照する場合があります。宣言された名前に外部リンケージがある場合、その名前によって参照されるエンティティの ID も共有されます。宣言された名前に内部リンケージがある場合、異なる翻訳単位の同じ名前は異なるエンティティを示しますが、同じ翻訳単位の異なるスコープでエンティティを参照できます。名前にリンケージがない場合、他のスコープからエンティティを参照することはできません。
(おっと...私が入力したものが、標準的な言葉遣いを繰り返しているだけであることがわかりました...)
言語仕様でカバーされていない他のいくつかの紛らわしい点もあります。
__attribute__
または__declspec
) またはコンパイラ オプションであり、イメージは翻訳単位から翻訳されたプログラム全体またはオブジェクト ファイルではないため、標準的な概念で正確に説明することはできません。シンボルは C++ の規範的な用語ではないため、関連する方言の拡張が広く採用されている場合でも、実装の詳細にすぎません。名前空間スコープ変数のリンケージ規則はconst
特別なものです (特にconst
、識別子のリンケージの概念を持つ C 言語のファイル スコープで宣言されたオブジェクトとは異なります)。ODRは C++ によって強制されるため、 functionsを除くプログラム全体で発生する同じ変数または関数の定義を 1 つだけ保持することが重要inline
です。のような特別なルールがない場合、複数の翻訳単位に含まれる (または 1 つの翻訳単位に複数回含まれる) ヘッダーまたはソース ファイル (多くの場合、「ヘッダー ファイル」) 内の初期化子 (例: ) を含む変数const
の最も単純な宣言。めったにありませんが) プログラム内で ODR に違反します。const
= xxx
const
いくつかのオブジェクトのようなマクロの代わりとして変数を使用することは不可能です。