外部連携と内部連携とは?


337

外部連携と内部連携の違いを知りたい。

の意味も知りたい

constとして宣言されていない限り、変数はデフォルトで内部的にリンクしますextern

回答:


278

あなたは(実装ファイルを書くとき.cpp.cxxなど)あなたのコンパイラが生成翻訳単位を。これは、実装のソースファイルと、その中にあるすべてのヘッダーです#include

内部リンケージは、翻訳単位の範囲内にあるすべてのものを指します。

外部リンケージは、特定の翻訳単位を超えて存在するものを指します。つまり、すべての翻訳単位(またはオブジェクトファイル)の組み合わせであるプログラム全体からアクセスできます。


112
グリッチを除いて私はこれに賛成します。翻訳単位は「どういうわけかオブジェクトファイル」ではなく、コンパイラオブジェクトファイルを作成するソースコードです。
sbi 2009

4
@FrankHB、答えが欠けている「より重要なもの」は何ですか?
数学者

2
@数学者最近申し訳ありません...私は問題が明白であると思います(言い回しの正確さ以外に)。const変数のルール(およびその目的)に関する質問はここでは完全に見逃されているため、この回答は不完全です。
FrankHB

293

以下のようdudewatは言っ 外部リンケージは、シンボル(関数やグローバル変数)は、プログラム全体を通してアクセス可能であることを意味し、内部には1つのでのみアクセス可能だとリンケージ手段翻訳単位

キーワードexternとを使用して、シンボルのリンクを明示的に制御できstaticます。リンケージが指定されていない場合、デフォルトのリンケージはexternconstシンボル用と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 { };
}

11
「export」キーワードの実装により、「静的」と宣言された関数と名前のない名前空間で宣言された関数の違いが強調されました。できる限り要約すると、ある翻訳単位でexportキーワードを使用して宣言された関数テンプレートは、2フェーズルックアップの結果として、別の翻訳単位の名前のない名前空間で定義された関数を参照できます。(ddj.com/showArticle.jhtml?articleID=184401584
リチャードコーデン

1.cpp <code> const int ci; </ code> 2.cpp <code> extern const int ci; </ code>
Rajendra

2
@Rajendaの場合、未解決のシンボルエラーが発生します(回答に9か月の遅延があったため申し訳ありませんが、このコメントを逃しました)。
Motti、2010年

4
この回答を大幅に強化する可能性がある情報:1)staticはC ++ 11では非推奨ではなくなりました。2)C ++ 11の匿名名前空間メンバーには、デフォルトで内部リンケージがあります。stackoverflow.com/questions/10832940/を

2
「外部リンクはあるが他の翻訳単位からは到達できない」とはどういう意味ですか?どのようにして到達できなくても外部にあるのでしょうか?
szx 2014年

101
  • グローバル変数には、デフォルトで外部リンケージがあります。そのスコープは、一致を与えることにより、それを含む以外のファイルに拡張できますextern、他のファイルで宣言ます。
  • グローバル変数のスコープは、宣言の前にキーワードを付けることで、その宣言を含むファイルに制限できますstatic。そのような変数は内部リンケージを持っていると言われています。

次の例を検討してください。

1.cpp

void f(int i);
extern const int max = 10;
int n = 0;
int main()
{
    int a;
    //...
    f(a);
    //...
    f(a);
    //...
}
  1. 関数のシグネチャは、外部リンケージがある関数としてf宣言fします(デフォルト)。その定義は、後でこのファイルまたは他の翻訳単位(下記に示す)で提供する必要があります。
  2. max整数定数として定義されます。定数のデフォルトのリンケージはinternalです。そのリンケージは、キーワードを使用して外部に変更されexternます。だから今max、他のファイルでアクセスできるようになりました。
  3. n整数変数として定義されます。関数本体の外部で定義された変数のデフォルトのリンケージは外部です。

2.cpp

#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;
}
  1. max外部リンケージがあると宣言されています。max(外部リンケージを使用する)の一致する定義は、いくつかのファイルに存在する必要があります。(1.cppと同様)
  2. n外部リンケージがあると宣言されています。
  3. zされている定義されたグローバル変数として内部リンケージ
  4. の定義は、functionを呼び出してもその値を保持する変数であることをnCall指定nCallしますf()。デフォルトの自動ストレージクラスを持つローカル変数とは異なりnCall、は、プログラムの起動時に1回だけ初期化され、の呼び出しごとに1回は初期化されませんf()。ストレージクラス指定子staticは、そのスコープではなく、ローカル変数の有効期間に影響します。

注意:キーワードstaticは2つの役割を果たします。グローバル変数の定義で使用する場合は、内部リンケージを指定します。ローカル変数の定義で使用される場合、変数の存続期間が関数の継続時間ではなくプログラムの継続時間になることを指定します。

お役に立てば幸いです。


2
重要なのは、ローカル変数の定義で使用すると、static遅延単一初期化が可能になります(グローバルなオブジェクトが必要だが、グローバルな構築順序の問題のためにいつ構築されるかを制御する必要があり、動的に割り当てることができない場合に役立ちます)使用new含意することによって、これは)、C ++を使用して組み込みシステム上の問題は主に、より詳細な初期化スキームは、当該オブジェクトの必要なものを超えてもよいです。
JAB 2015年

1
とても良い試験、私の一日を作りました。
Blood-HaZaRd

28

'C'に関して(静的キーワードは 'C'と 'C ++'で異なる意味を持つため)

「C」のさまざまなスコープについて話しましょう

スコープ:基本的に、私は何かをどのくらい遠くまで見ることができますか。

  1. ローカル変数:スコープは関数内のみです。RAMのスタック領域にあります。つまり、関数が呼び出されるたびに、関数の引数を含め、その関数の一部であるすべての変数が新たに作成され、コントロールが関数から出ると破棄されます。(関数が戻るたびにスタックがフラッシュされるため)

  2. 静的変数:このスコープはファイル用です。
    宣言されているファイルのどこからでもアクセスできます。RAMのDATAセグメントに存在します。これはファイル内でしかアクセスできないため、内部リンクです。任意の
    他のファイルには、この変数を参照することはできません。実際、STATICキーワードは、
    「C」にデータや関数の非表示を導入できる唯一の方法です。

  3. グローバル変数:このスコープはアプリケーション全体です。アプリケーションのどこからでもアクセスできます。グローバル変数もDATAセグメントにあります。アプリケーション内のどこからでもアクセスできるため、外部リンク

デフォルトでは、すべての関数がグローバルです。ファイル内の一部の関数を外部から非表示にする必要がある場合は、関数の前にstaticキーワードを付けることができます。:-)


12
@Libin:1)と同様に、ローカル変数はスタック上にある必要はありません-それらは通常スタック上にありますが、ARM環境ではスタック上よりもレジスタ内にあることがよくあります(いくつかの要因によって異なります-呼び出しレベル、数値)正式な引数の..)
Artur

4
@Libin:1)については、「フラッシュ」を上書きと見なす場合-これは誤りです。スタックポインターが別の場所に移動するだけです。「以前は有効だったローカル変数」は「フラッシュ」/クリアなどされません。変数のスコープとストレージ期間を混在させます。スコープは、どこから変数にアクセスできるかを示します。保存期間は、それが存在する期間を示します。静的な保存期間を持つローカル変数を持つことができます。それは「永遠に」住んでいる意味が、それが中で宣言された関数からアクセスすることができます。
アルトゥル

2
不正確な概念と明らかな誤解に対する反対投票。厳密に言うと、Cには「グローバル」も「変数」も(名詞として)定義されていません。「グローバル変数」ではなく「ファイルスコープオブジェクト」を参照したいかもしれませんが、「スコープ」(C 識別子のプロパティです)はナンセンスです。(どちらの用語もC ++で規範的にわずかに異なる意味で定義されています。)
FrankHB

@Arturは、「のみ」を忘れたと思います。「永久に」存続することを意味しますが、宣言された関数から(のみ)アクセスできます。- これは重要な詳細なので、指摘したいと思います明示的に。
RobertSは

1
@RobertSsupportsMonicaCellio-あなたは正しい
Artur

14

質問について話す前に、「翻訳単位」、「プログラム」、およびC ++のいくつかの基本概念(実際には、リンケージは一般にその1つです)を正確に理解することをお勧めします。また、スコープとは何かを知る必要があります

特にいくつかの重要なポイントを強調します。以前の回答で不足しているもの。

リンケージ名前のプロパティであり、宣言によって導入されます。異なる名前が同じエンティティ(通常はオブジェクトまたは関数)を表す場合があります。リンケージについて話します、エンティティが特定の宣言(通常は1つの宣言)からの一意の名前によってのみ参照されることが確実でない限り、エンティティのは通常ナンセンスです。

オブジェクトはエンティティですが、変数であることに注意してくださいははないことに。変数のリンケージについて説明するとき、実際には、(特定の宣言によって導入される)指定されたエンティティーの名前が関係します。名前のリンケージは、リンケージなし、内部リンケージ、または外部リンケージの3つのうちの1つです。

異なる翻訳単位は、ヘッダー/ソースファイル(はい、それは標準の表現です)を含めることで同じ宣言を共有できます。そのため、同じ名前を異なる翻訳単位で参照できます。宣言された名前に外部リンケージがある場合、その名前で参照されるエンティティのIDも共有されます。宣言された名前に内部リンケージがある場合、異なる翻訳単位の同じ名前は異なるエンティティを示しますが、同じ翻訳単位の異なるスコープのエンティティを参照できます。名前にリンケージがない場合、エンティティを他のスコープから参照することはできません。

(おっと...私が入力したのは、標準的な言葉遣いを幾分か繰り返すだけだった...)

言語仕様ではカバーされていない他のいくつかの混乱する点もあります。

  1. (名前の)可視性。これも宣言された名前のプロパティですが、リンケージとは意味が異なります。
  2. 可視性(副作用)。これはこのトピックとは関係ありません。
  3. (シンボルの)可視性。この概念は、実際の実装使用できます。このような実装では、オブジェクト(バイナリ)コードで特定の可視性を持つシンボルは通常、ソース(C ++)コードで同じ特定のリンケージを持つ名前を持つエンティティ定義からマップされたターゲットです。ただし、通常は1対1になるとは限りません。たとえば、動的ライブラリイメージ内のシンボルは、そのイメージ内でソースコードから内部でのみ共有するように指定できます(通常、一部の拡張機能に関係します)。__attribute__、または__declspec)またはコンパイラオプション。画像はプログラム全体でも、翻訳単位から翻訳されたオブジェクトファイルでもないため、標準の概念では正確に説明できません。シンボルはC ++では規範的な用語ではないため、関連する方言の拡張が広く採用されている場合でも、これは実装の詳細にすぎません。
  4. アクセシビリティ。C ++では、これは通常、クラスメンバーまたは基本クラスのプロパティに関するものであり、これもトピックとは無関係の別の概念です。
  5. グローバル。C ++では、「グローバル」とは、グローバルネームスペースまたはグローバルネームスペーススコープを指します。後者は、C言語のファイルスコープとほぼ同じです。CとC ++の両方で、リンケージはスコープとは関係ありませんが、スコープ(リンケージなど)は、宣言によって導入された識別子(Cの場合)または名前(C ++の場合)にも密接に関係しています。

名前空間スコープconst変数リンケージルールは特別なものです(constC言語のファイルスコープで宣言されているオブジェクトとは異なり、識別子のリンケージの概念もあります)。以来ODRは、 C ++によって強制され、同じ変数や関数の1以下の定義は除いプログラム全体で発生していない維持することが重要であるinline機能。そのような特別な規則がない場合、複数の翻訳単位に含まれる(または複数の翻訳単位に複数回含まれる)ヘッダーまたはソースファイル(多くの場合「ヘッダーファイル」)に初期化子(例const:)を含むconst変数の最も単純な宣言= xxx、まれですが)プログラムでODRに違反しますconst 一部のオブジェクトのようなマクロの置換として変数は不可能です。


3
この答えは非常に熟練しており、非常に正確であるかもしれません(私はそれを判断できません)が、言語の仕様を直接読む代わりに、ここでこの質問を調べている多くの人々が望むほど理解できないかもしれません。少なくとも私のニーズに対しては、受け入れられた答えを使用しますが、言語仕様について少し洞察を与えてくれてありがとう。👍🏻
WEDI

8

C ++の内部と外部のリンケージが明確で簡潔な説明を与える思います:

翻訳単位とは、実装(.c / .cpp)ファイルと、それに含まれるすべてのヘッダー(.h / .hpp)ファイルを指します。そのような翻訳単位内のオブジェクトまたは関数に内部リンケージがある場合、その特定のシンボルは、その翻訳単位内のリンカーにのみ表示されます。オブジェクトまたは関数に外部リンケージがある場合、リンカは他の翻訳単位を処理するときにもそれを見ることができます。staticキーワードをグローバル名前空間で使用すると、シンボルに内部リンケージが強制されます。externキーワードは、外部リンケージを持つシンボルになります。

コンパイラーは、次のようなシンボルのリンケージをデフォルト設定します。

非constグローバル変数にはデフォルトで外部リンケージがあります
Constグローバル変数にはデフォルトで内部リンケージがあります
関数にはデフォルトで外部リンケージがあります


6

リンケージは、同じ名前の識別子が同じオブジェクト、関数、または他のエンティティを参照しているかどうかを判断します。これらの識別子が異なる翻訳単位で表示されている場合でも同じです。識別子のリンケージは、それがどのように宣言されたかによって異なります。リンケージには3つのタイプがあります。

  1. 内部リンケージ:識別子は翻訳単位内でのみ確認できます。
  2. 外部リンケージ:識別子は、他の翻訳単位で表示(および参照)できます。
  3. リンケージなし:識別子は、それらが定義されているスコープでのみ表示できます。リンケージはスコープに影響しません

C ++のみ:C ++コードフラグメントと非C ++コードフラグメントの間にリンケージを作成することもできます。これは言語リンケージと呼ばれます

出典:IBMプログラムリンケージ


5

基本的に

  • extern linkage 変数はすべてのファイルに表示されます
  • internal linkage 変数は単一のファイルに表示されます。

説明:externとして宣言されていない限り、const変数はデフォルトで内部的にリンクします

  1. デフォルトでは、グローバル変数は external linkage
  2. しかし、constグローバル変数はinternal linkage
  3. 余分extern constなグローバル変数はexternal linkage

C ++でのリンケージに関するかなり良い資料

http://www.goldsborough.me/c/c++/linker/2016/03/30/19-34-25-internal_and_external_linkage_in_c++/


1

C ++の場合

ファイルスコープにあり、クラスまたは関数内にネストされていない変数は、プログラムのすべての変換単位で表示されます。これは外部リンケージと呼ばれます。リンク時に、その名前はその翻訳単位の外部にあるリンカから見えるためです。

グローバル変数と通常の関数には外部リンケージがあります。

ファイルスコープの静的オブジェクトまたは関数名は、変換単位に対してローカルです。それは内部リンケージと呼ばれています

リンケージは、リンク/ロード時にアドレスを持つ要素のみを参照します。したがって、クラス宣言とローカル変数にはリンケージがありません。


constグローバル変数には内部リンクがあります。
Blood-HaZaRd
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.