リンケージ

提供: RAD Studio
移動先: 案内検索

宣言:インデックス への移動

通常,実行可能プログラムは,いくつかの独立した翻訳単位をコンパイルして,その結果として得られたオブジェクトファイルを既存のライブラリとリンクすることによって生成されます。同一の識別子が異なるスコープ内(たとえば,異なるファイル)で宣言された場合,あるいは同一スコープ内で複数回宣言された場合には問題が発生します。リンケージは,1 つの識別子の各インスタンスが特定の 1 つのオブジェクトあるいは関数と,正しく結び付けられるようにする過程です。すべての識別子は,それぞれのスコープに密接に関連したリンク属性を持ちます。リンク属性は,外部リンケージ,内部リンケージ,リンケージなしのいずれかです。これらの属性は,宣言の位置と形式,および記憶クラス指定子 static あるいは extern を明示的に(あるいはデフォルトによって暗黙に)使うことによって決定されます。

外部リンケージを持つ識別子のインスタンスは,プログラムを構成するすべてのファイルとライブラリの中で,ただ 1 つのオブジェクトあるいは関数を表します。内部リンケージを持つ識別子のインスタンスは,1 つのファイル内でのみ,ただ 1 つのオブジェクトあるいは関数を表します。リンケージなしの識別子は,ユニークな存在を意味します。

外部リンケージと内部リンケージの規則

ファイルスコープを持つすべてのオブジェクトあるいはファイル識別子は,その宣言に記憶クラス指定子 static が含まれている場合は,内部リンケージを持ちます。

C では,1 つの識別子が同一のファイル内で内部リンケージと外部リンケージの両方を持つ場合,その識別子は内部リンケージを持つことになります。C++ では,このような場合には外部リンケージを持つことになります。

オブジェクトあるいは関数の宣言に記憶クラス指定子 extern が含まれている場合,その識別子はファイルスコープを持つ識別子のすべての可視の宣言と同一のリンケージを持つことになります。可視の宣言がなければ,その識別子は外部リンケージを持つことになります。

記憶クラス指定子を使用せずに関数の宣言が行われた場合,そのリンケージは記憶クラス指定子 extern が使用されたものとして決定されます。

ファイルスコープを持つオブジェクト識別子の宣言が記憶クラス指定子なしで行われた場合,その識別子は外部リンケージを持つことになります。

リンケージ属性を持たない識別子

  • オブジェクトあるいは関数以外の識別子(たとえば typedef 識別子)として宣言されたもの
  • 関数パラメータ
  • 記憶クラス指定子 extern を使用せずに宣言されたオブジェクトのブロックスコープ識別子

名前の変形

C++ モジュールをコンパイルするとき,コンパイラは関数の引数の型をコード化した内容を含む関数名を生成します。これを,名前の変形(name mangling)といいます。これによって関数のオーバーロードが可能になり,ほかのモジュールにある関数の呼び出しにおいてリンカがエラーを検出するのに役立ちます。ただし,名前を変形したくないこともあります。変形された名前を含まないモジュールとリンクする C++ のモジュールをコンパイルするときは,C++ コンパイラにほかのモジュールにある関数の名前を変形しないことを指示しなければなりません。たとえば,C コンパイラでコンパイルしたライブラリや,.obj ファイルをリンクするときにこうした問題が生じます。

C++ コンパイラに関数の名前を変形しないように指示するには,次のように extern "C" として関数を宣言します。



 extern "C" void Cfunc( int );



この宣言は,関数 Cfunc の参照を変形しないようにコンパイラに伝えます。

いくつかの名前のブロックを一度に extern "C" 宣言することもできます。



 extern "C" {
    void Cfunc1( int );
    void Cfunc2( int );
    void Cfunc3( int );
 };



単一の関数を宣言するのと同じように,この宣言は関数 Cfunc1,Cfunc2,Cfunc3 への参照は名前を変形しないことをコンパイラに指示します。ブロック宣言のこの形式は,関数名のブロックがヘッダーファイル中に含まれるときにも使うことができます。



 extern "C" {
    #include "locallib.h"
 };



メモ:  extern "C" をクラス識別子とともに用いることはできません。

関連項目