web-dev-qa-db-ja.com

外部リンケージと内部リンケージとは何ですか?

外部リンクと内部リンク、およびそれらの違いを理解したいと思います。

また、の意味を知りたい

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

306
rkb

実装ファイル(.cpp.cxxなど)を作成すると、コンパイラーは翻訳単位を生成します。これは、実装ファイルのオブジェクトファイルと、その中の#includedのすべてのヘッダーです。

内部リンケージは、すべてを指す翻訳単位の範囲内

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

244
dudewat

dudewat saidexternalリンケージは、シンボル(関数またはグローバル変数)がプログラム全体でアクセス可能であり、internalリンケージは、1つの translation unit でのみアクセス可能であることを意味します。

externおよびstaticキーワードを使用して、シンボルのリンケージを明示的に制御できます。リンケージが指定されていない場合、デフォルトのリンケージは、_externシンボルではconststaticシンボルでは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 を使用して、classesを入れることもできます。匿名名前空間のリンケージはC++ 98とC++ 11の間で変更されましたが、主なことは、他の翻訳単位から到達できないことです。

namespace {
   int i; // external linkage but unreachable from other translation units.
   class invisible_to_others { };
}
269
Motti
  • グローバル変数には、デフォルトでexternalリンケージがあります。そのスコープは、他のファイルで一致する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をexternalリンケージ(デフォルト)を持つ関数として宣言します。その定義は、後でこのファイルまたは他の翻訳単位で提供する必要があります(以下を参照)。
  2. maxは整数定数として定義されます。定数のデフォルトのリンケージはinternalです。そのリンケージは、キーワードexternで外部に変更されます。したがって、他のファイルでmaxにアクセスできます。
  3. nは整数変数として定義されます。関数本体の外部で定義された変数のデフォルトのリンケージはexternalです。

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

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

お役に立てば幸いです!

86
Rajendra Uppal

「C」に関して(静的キーワードの意味は「C」と「C++」で異なるため)

「C」で異なるスコープについて話しましょう

範囲:基本的に、どれくらいの時間、どこまで見ることができるかです。

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

  2. 静的変数:このスコープはファイル用です。ファイル内のすべての場所にアクセスできます
    宣言されています。 RAMのDATAセグメントにあります。これはファイル内でのみアクセスできるため、内部リンケージです。どれか
    他のファイルはこの変数を見ることができません。実際、STATICキーワードは、あるレベルのデータまたは機能を導入できる唯一の方法です
    「C」に隠れています

  3. グローバル変数:これの範囲はアプリケーション全体です。アプリケーションのどこからでもアクセスできます。グローバル変数はDATAセグメントにも存在します。これは、アプリケーション内のすべての場所にアクセスできるため、外部リンクです。

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

25
Libin Jose

質問について話す前に、用語 translation unitprogram およびC++の一部の 基本概念 (実際にはリンケージは一般にそれらの1つです)。 scope とは何かを知る必要もあります。

私はいくつかの重要なポイント、特にを強調します。以前の回答にないもの。

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

objectはエンティティですが、variableはエンティティではありません。変数のリンケージについては、実際には、指定されたエンティティ(特定の宣言によって導入される)の名前が関係します。名前のリンケージは、リンケージなし、内部リンケージ、または外部リンケージの3つのうちの1つです。

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

(おっと...私が入力したのは、やや繰り返しているだけだとわかった 標準の言い回し ...)

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

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

名前空間スコープconst変数のリンクルール は特別なものです(特に、識別子のリンケージの概念を持つC言語のファイルスコープで宣言されたconstオブジェクトとは異なります)。 ODR はC++によって実施されるため、 inline関数を除くプログラム全体で発生した同じ変数または関数の定義を1つだけ保持することが重要ですconstのような特別なルールがない場合、複数の翻訳単位に含まれる(または1つの翻訳単位に含まれる)ヘッダーまたはソースファイル(多くの場合「ヘッダーファイル」)にイニシャライザー(= xxxなど)を持つconst変数の最も単純な宣言プログラム内でODRに違反することはめったにありませんが、これによりconst変数を一部のオブジェクトのようなマクロの置換として使用できなくなります。

10
FrankHB

C++の内部および外部リンク は、明確で簡潔な説明を与えると思います。

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

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

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

5
Nan Xiao

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

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

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

ソース: IBM Program Linkage

4
arun pal

基本的に

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

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

  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++/

4
Color

C++の場合

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

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

静的ファイルスコープのオブジェクト名または関数名は翻訳単位に対してローカルです。それはInternal Linkageと呼ばれます

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

0
Saurabh Raoot