401

外部リンケージと内部リンケージとその違いを理解したい。

の意味も知りたい

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

4

9 に答える 9

345

実装ファイル ( .cpp.cxxなど) を作成すると、コンパイラによって翻訳単位が生成されます。これは、実装のソース ファイルと、それに含まれるすべてのヘッダーです#include

内部リンケージは、翻訳単位の範囲内でのみすべてを参照します。

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

于 2009-08-31T17:59:03.887 に答える
332

dudewatが言ったよう に、外部リンケージはシンボル(関数またはグローバル変数)がプログラム全体でアクセスできることを意味し、内部リンケージは1つの翻訳単位でのみアクセスできることを意味します。

externおよびstaticキーワードを使用して、シンボルのリンケージを明示的に制御できます。リンケージが指定されていない場合、デフォルトのリンケージは、非シンボルの場合はextern(外部リンケージ) であり、シンボルの場合は(内部リンケージ) です。conststaticconst

// 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
}
于 2009-08-31T18:37:43.510 に答える
122
  • グローバル変数には、デフォルトで外部リンケージがあります。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. function のシグネチャは、外部リンケージを持つ関数としてf宣言します (デフォルト)。その定義は、このファイルまたは他の翻訳単位 (以下に示す) で後で提供する必要があります。f
  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外部リンケージを持つと宣言されています。max(外部リンケージを使用した)の一致する定義が何らかのファイルに含まれている必要があります。(1.cppのように)
  2. n外部リンケージを持つと宣言されています。
  3. z内部リンケージを持つグローバル変数として定義れています。
  4. の定義は、 function の呼び出し間で値を保持する変数であることをnCall指定します。デフォルトの auto ストレージ クラスのローカル変数とは異なり、はプログラムの開始時に 1 回だけ初期化され、 の呼び出しごとに 1 回ではありません。ストレージ クラス指定子は、スコープではなく、ローカル変数の有効期間に影響します。nCallf()nCallf()static

注意:キーワードstaticには 2 つの役割があります。グローバル変数の定義で使用すると、内部リンケージを指定します。ローカル変数の定義で使用すると、変数の有効期間が関数の期間ではなく、プログラムの期間になることを指定します。

それが役立つことを願っています!

于 2010-02-26T19:21:59.650 に答える
31

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

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

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

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

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

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

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

于 2010-08-12T11:46:26.137 に答える
18

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

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

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

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

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

(おっと...私が入力したものが、標準的な言葉遣いを繰り返しているだけであることがわかりました...)

言語仕様でカバーされていない他のいくつかの紛らわしい点もあります。

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

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

于 2016-09-06T14:26:01.007 に答える