C++
言語リンケージは、とnon-C++
コード フラグメント間のリンケージに使用される用語です。通常、C++ プログラムでは、すべての関数名、関数型、さらには変数名にもデフォルトの C++ 言語リンケージがあります。
C
C++ オブジェクト コードは、定義済みのリンケージ指定子を使用して、他のソース言語 ( など) を使用して生成された別のオブジェクト コードにリンクできます。
の概念を認識している必要があるためname mangling
、関数名、関数型、および変数名をエンコードして、それらに一意の名前を生成します。これにより、リンカーは一般的な名前を区別できます (関数のオーバーロードの場合と同様)。C モジュールを C++ コンパイラでコンパイルされたライブラリまたはオブジェクト ファイルとリンクする場合、名前マングリングは望ましくありません。このような場合の名前マングリングを防ぐために、リンケージ指定子が使用されます。この場合、extern "C"
はリンケージ指定子です。例を見てみましょう (ここで言及されている C++ コード):
typedef int (*pfun)(int); // line 1
extern "C" void foo(pfun); // line 2
extern "C" int g(int) // line 3
...
foo( g ); // Error! // line 5
pfun
行 1では、リンケージ指定子がないため、C++ 関数を指すように宣言しています。
したがって、2 行目では、foo が C++ 関数へのポインターを受け取る C 関数であることを宣言しています。
5 行目では、型が一致しない C 関数である g へのポインターを使用して foo を呼び出そうとしています。
関数名のリンケージの違い:
2 つの異なるファイルを見てみましょう。
リンケージのあるものextern "c"
(file1.cpp):
#include <iostream>
using namespace std;
extern "C"
{
void foo (int a, int b)
{
cout << "here";
}
}
int main ()
{
foo (10,20);
return 0;
}
リンクのないextern "c"
もの (file2.cpp):
#include <iostream>
using namespace std;
void foo (int a, int b)
{
cout << "here";
}
int main ()
{
foo (10,20);
return 0;
}
これら 2 つをコンパイルして、objdump を確認します。
# g++ file1.cpp -o file1
# objdump -Dx file1
# g++ file2.cpp -o file2
# objdump -Dx file2
extern "C" リンケージでは、関数の名前マングリングはありませんfoo
。したがって、それを使用しているすべてのプログラム (それから共有ライブラリを作成すると仮定) は、名前マングリングの影響を考慮せずに(dlsym
およびのようなヘルパー関数を使用して) foo を直接呼び出すことができます。dlopen
0000000000400774 <foo>:
400774: 55 push %rbp
400775: 48 89 e5 mov %rsp,%rbp
....
....
400791: c9 leaveq
400792: c3 retq
0000000000400793 <main>:
400793: 55 push %rbp
400794: 48 89 e5 mov %rsp,%rbp
400797: be 14 00 00 00 mov $0x14,%esi
40079c: bf 0a 00 00 00 mov $0xa,%edi
4007a1: e8 ce ff ff ff callq 400774 <foo>
4007a6: b8 00 00 00 00 mov $0x0,%eax
4007ab: c9 leaveq
一方、 noextern "C"
が使用されている場合、 func:foo
はいくつかの事前定義されたルール (使用されているコンパイラ/リンカーに知られている) でマングルされるため、アプリケーションは名前を として指定して直接呼び出すことができませんfoo
。_Z3fooii
ただし、必要に応じてマングル名 (この場合) で呼び出すこともできますが、明らかな理由で誰も使用しません。
0000000000400774 <_Z3fooii>:
400774: 55 push %rbp
400775: 48 89 e5 mov %rsp,%rbp
...
...
400791: c9 leaveq
400792: c3 retq
0000000000400793 <main>:
400793: 55 push %rbp
400794: 48 89 e5 mov %rsp,%rbp
400797: be 14 00 00 00 mov $0x14,%esi
40079c: bf 0a 00 00 00 mov $0xa,%edi
4007a1: e8 ce ff ff ff callq 400774 <_Z3fooii>
4007a6: b8 00 00 00 00 mov $0x0,%eax
4007ab: c9 leaveq
4007ac: c3 retq
このページは、この特定のトピックについても読むのに適しています。
呼び出し規約に関するわかりやすく明確に説明された記事: http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx