質問

っては、プログラミング言語コースというの extern "C" 宣言です。

どのようなこの宣言でより深いレベル以外でフで、CとC++に"?どのようなこのバインディングが、プログラムでも見ることができますか?

役に立ちましたか?

解決

extern "C" 次の記号がそうでないことを確認するために使用されます 壊れた (装飾)。


例:

電話と呼ばれるファイルに次のコードがあるとしましょう test.cpp:

extern "C" {
  int foo() {
    return 1;
  }
}

int bar() {
  return 1;
}

走ったら gcc -c test.cpp -o test.o

シンボル名を見てください:

00000010 T _Z3BARV

000000 T foo

foo() その名前を保持します。

他のヒント

CとC ++の両方でコンパイルできる典型的な関数を見てみましょう。

int Add (int a, int b)
{
    return a+b;
}

現在、関数は内部的に「_Add」と呼ばれます。一方、C ++関数は、Name-Manglingと呼ばれるシステムを使用して内部的に完全に異なるものと呼ばれます。基本的には、異なるパラメーターを持つ同じ関数が異なる内部名を持つように関数に名前を付ける方法です。

したがって、add()がadd.cで定義されている場合、add.hにプロトタイプがある場合、c ++ファイルにadd.hを含めようとすると問題が発生します。 C ++コードは、add.cの名前とは異なる名前の関数を探しているため、リンカーエラーが表示されます。その問題を回避するには、この方法でadd.cを含める必要があります。

extern "C"
{
#include "add.h"
}

これで、C ++コードは、C ++名のマングルバージョンの代わりに_ADDとリンクします。

それは表現の用途の1つです。結論として、C ++プログラムで厳密にCであるコードをコンパイルする必要がある場合(Statementまたはその他の手段を含む)、Extern "C" {...}宣言でそれをラップする必要があります。

Extern "C"でコードブロックにフラグを立てると、Cスタイルのリンケージを使用するようシステムに指示しています。

これは、主に、リンカーが名前をマングルする方法に影響します。 C ++スタイル名のマングリング(オペレーターの過負荷をサポートするためにより複雑です)を使用する代わりに、リンカーから標準のCスタイルの命名を取得します。

C ++では、関数の名前/記号は、実際には、異なるクラス/名前空間が同じ署名の関数を持つことができるように、他の何かに変更されます。 Cでは、関数はすべてグローバルに定義されており、そのようなカスタマイズされた名前変更プロセスは必要ありません。

C ++とCに相互に話しかけるために、「Extern C」はコンパイラにCコンベンションを使用しないように指示します。

注意すべきこと extern "C" また、関数の種類を変更します。より低いレベルで物事を変更するだけではありません:

extern "C" typedef void (*function_ptr_t)();

void foo();

int main() { function_ptr_t fptr = &foo; } // error!

タイプの &foo Typedefが指定するタイプに等しくありません(ただし、コードは一部に受け入れられますが、すべてのコンパイラではありませんが)。

Extern Cは、C ++コンパイラによる名前のマングリングに影響します。 C ++コンパイラに名前をマングル化しないようにする方法、またはCコンパイラと同じ方法でそれらをマングルする方法です。これは、CとC ++のインターフェイスの方法です。

例として:

extern "C" void foo(int i);

関数をCモジュールに実装できるようにしますが、C ++モジュールから呼び出されます。

C ++モジュールで定義されているC ++関数(明らかにCはC ++クラスを使用できない)を呼び出すようにCモジュールを取得しようとすると、問題が発生します。 Cコンパイラは好きではありません extern "C".

したがって、これを使用する必要があります:

#ifdef __cplusplus
extern "C" {
#endif

void foo(int i);

#ifdef __cplusplus
}
#endif

これがヘッダーファイルに表示されると、C ++コンパイラとC ++の両方が宣言に満足し、C ++モジュールまたはC ++モジュールのいずれかで定義できるようになり、C ++コードとC ++コードの両方で呼び出すことができます。

extern"C"の場合は、同封のコードC-スタイルリンク名の難号化.C++を使用し複雑な名前の難号化形式です。次に例を示します。

http://en.wikipedia.org/wiki/Name_mangling

int example(int alpha, char beta);

C: _example

C++: __Z7exampleic

更新:としてGManNickGメのパターンの名の難号化するコンパイラに依存します。

extern "c"は、CコンパイラとC ++コンパイラがオブジェクトファイルの異なる形式にソースを変換するため、Cバインディングで関数を宣言するためのキーワードです。

たとえば、コードスニペットは次のとおりです。

int _cdecl func1(void) {return 0}
int _stdcall func2(int) {return 0}
int _fastcall func3(void) {return 1}

32ビットCコンパイラは、次のようにフォームのコードを翻訳します。

_func1
_func2@4
@func3@4

CDECLでは、FUNC1は 'として翻訳されます_名前'

stdcallでは、func2は 'として翻訳されます_Name@x'

FastCallでは、FUNC2は 'として翻訳されます@name@x'

'バツ'パラメーターリストのパラメーターのバイト数を意味します。

64ビットのWindowsでは、主要なアンダースコアはありません

C ++では、クラス、テンプレート、名前空間、およびオペレーターのオーバーロードが導入されます。同じ名前の2つの関数が許可されていないため、C ++コンパイラはシンボル名でタイプ情報を提供します。

たとえば、コードスニペットは次のとおりです。

int func(void) {return 1;}
int func(int) {return 0;}
int func_call(void) {int m=func(), n=func(0);}

C ++コンパイラは、次のようにコードを翻訳します。

int func_v(void) {return 1;}
int func_i(int) {return 0;}
int func_call(void) {int m=_func_v(), n=_func_i(0);}

「_V」と「_i」は「void」と「int」のタイプ情報です

これがMSDNからの引用です

「externキーワードは変数または関数を宣言し、外部リンケージがあることを指定します(その名前は定義されているファイル以外のファイルから表示されます)。変数を変更すると、externは変数に静的な時間があることを指定します(割り当てられています。変数または関数は、別のソースファイル、または同じファイルで定義される場合があります。ファイルスコープでの変数と関数の宣言は、デフォルトで外部にあります。」

http://msdn.microsoft.com/en-us/library/0603949d%28vs.80%29.aspx

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top