C ++コードに入れることは正確に何をextern "C"
しますか?
例えば:
extern "C" {
void foo();
}
C ++コードに入れることは正確に何をextern "C"
しますか?
例えば:
extern "C" {
void foo();
}
extern "C"
C++ の関数名に C リンケージを持たせ (コンパイラは名前をマングルしません)、クライアントの C コードが、関数の宣言だけを含む C 互換ヘッダー ファイルを使用して関数にリンク (使用) できるようにします。関数定義は、クライアント C リンカーが C 名を使用してリンクするバイナリ形式 (C++ コンパイラによってコンパイルされたもの) に含まれています。
C++ には関数名のオーバーロードがあり、C にはないため、C++ コンパイラは関数名をリンク先の一意の ID として使用することはできず、引数に関する情報を追加して名前をマングルします。C では関数名をオーバーロードできないため、AC コンパイラは名前をマングルする必要はありません。C++ で関数にextern "C"
リンケージがあると述べる場合、C++ コンパイラは、リンケージに使用される名前に引数/パラメーターの型情報を追加しません。
ご存知のように、extern "C"
個々の宣言/定義へのリンケージを明示的に指定するか、ブロックを使用して宣言/定義のシーケンスをグループ化し、特定のリンケージを持たせることができます。
extern "C" void foo(int);
extern "C"
{
void g(char);
int i;
}
専門的なことが気になる場合は、C++03 標準のセクション 7.5 に記載されています。ここに簡単な要約を示します (強調部分はextern "C"
)。
extern "C"
リンケージ仕様ですextern "C"
クラスメンバーに対しては無視されますextern "C"
関数に外部リンケージを強制します (静的にすることはできません)static
extern "C"
まだ投稿されていなかったので、少し情報を追加したかっただけです。
次のような C ヘッダーのコードをよく見かけます。
#ifdef __cplusplus
extern "C" {
#endif
// all of your legacy C code here
#ifdef __cplusplus
}
#endif
これにより、マクロ「__cplusplus」が定義されるため、その C ヘッダー ファイルを C++ コードで使用できるようになります。ただし、マクロが定義されていない従来の C コードでも引き続き使用できるため、一意の C++ 構造は表示されません。
ただし、次のような C++ コードも見たことがあります。
extern "C" {
#include "legacy_C_header.h"
}
ほぼ同じことを達成していると思います。
どちらが良いかはわかりませんが、私は両方を見てきました。
すべてのC++プログラムでは、すべての非静的関数がバイナリファイルでシンボルとして表されます。これらの記号は、プログラム内の機能を一意に識別する特別なテキスト文字列です。
Cでは、シンボル名は関数名と同じです。これが可能なのは、Cでは2つの非静的関数が同じ名前を持つことができないためです。
C ++はオーバーロードを許可し、Cにはない多くの機能(クラス、メンバー関数、例外仕様など)を備えているため、単に関数名をシンボル名として使用することはできません。これを解決するために、C ++はいわゆる名前マングリングを使用します。これは、関数名とすべての必要な情報(引数の数やサイズなど)を、コンパイラーとリンカーによってのみ処理される奇妙な文字列に変換します。
したがって、extern Cとして関数を指定した場合、コンパイラーはその関数との名前マングリングを実行せず、関数名としてそのシンボル名を使用して直接アクセスできます。
dlsym()
これは、そのような関数を使用したりdlopen()
呼び出したりするときに便利です。
ほとんどのプログラミング言語は、既存のプログラミング言語の上に構築されていません。C++ は C の上に構築されており、さらに手続き型プログラミング言語から構築されたオブジェクト指向プログラミング言語です。そのため、Cとのextern "C"
下位互換性を提供するC++ 式が存在します。
次の例を見てみましょう。
#include <stdio.h>
// Two functions are defined with the same name
// but have different parameters
void printMe(int a) {
printf("int: %i\n", a);
}
void printMe(char a) {
printf("char: %c\n", a);
}
int main() {
printMe('a');
printMe(1);
return 0;
}
AC コンパイラは上記の例をコンパイルしません。これは、同じ関数printMe
が 2 回定義されているためです (パラメータint a
vsが異なっていてもchar a
)。
gcc -o printMe printMe.c && ./printMe;
1 エラー。PrintMe が複数回定義されています。
C++ コンパイラは上記の例をコンパイルします。printMe
2 回定義されてもかまいません。
g++ -o printMe printMe.c && ./printMe;
これは、C++ コンパイラがパラメーターに基づいて暗黙的に関数の名前を変更 ( mangles ) するためです。C では、この機能はサポートされていませんでした。ただし、C++ が C の上に構築されたとき、言語はオブジェクト指向になるように設計されており、同じ名前のメソッド (関数) でさまざまなクラスを作成し、さまざまなメソッドに基づいてメソッドをオーバーライドする (メソッドのオーバーライド) 機能をサポートする必要がありました。パラメーター。
extern "C"
「C関数名をマングルしないでください」と言いますただし、「parent.c」というinclude
名前のレガシー C ファイルがあり、他のレガシー C ファイル「parent.h」、「child.h」などの関数名を使用しているとします。レガシー「parent.c」ファイルが実行された場合C++ コンパイラを使用すると、関数名がマングルされ、「parent.h」、「child.h」などで指定された関数名と一致しなくなります。したがって、これらの外部ファイルの関数名も必要になります。めちゃくちゃになる。多くの依存関係を持つ複雑な C プログラム全体で関数名をマングリングすると、コードが壊れる可能性があります。そのため、C++ コンパイラに関数名をマングルしないように指示できるキーワードを提供すると便利な場合があります。
このextern "C"
キーワードは、C 関数名をマングル (名前変更) しないように C++ コンパイラに指示します。
例えば:
extern "C" void printMe(int a);
extern "C" でラップするだけでは、C ヘッダーを C++ と互換性を持たせることはできません。C ヘッダーの識別子が C++ キーワードと競合する場合、C++ コンパイラはこれについて文句を言います。
たとえば、次のコードが g++ で失敗するのを見てきました。
extern "C" {
struct method {
int virtual;
};
}
ちょっと理にかなっていますが、C コードを C++ に移植するときに留意すべき点です。
関数がCから呼び出せるように、関数のリンクを変更します。実際には、関数名がマングルされていないことを意味します。
CとC++でコンパイルされた関数の名前はリンク段階で異なるため、リンク時にCスタイルでこれらの関数の名前を検索するようにC++コンパイラに通知します。
extern "C"
これは、C++ コンパイラによって認識され、その関数が C スタイルでコンパイルされている (またはこれからコンパイルされる) ことをコンパイラに通知することを目的としています。これにより、リンク時に C の正しいバージョンの関数にリンクされます。
extern "C"
Cpp ソース ファイルでC 関数を呼び出すために使用されるリンケージ仕様です。C 関数を呼び出し、変数を書き、ヘッダーを含めることができます。関数は extern エンティティで宣言され、外部で定義されています。構文は
タイプ 1:
extern "language" function-prototype
タイプ 2:
extern "language"
{
function-prototype
};
例えば:
#include<iostream>
using namespace std;
extern "C"
{
#include<stdio.h> // Include C Header
int n; // Declare a Variable
void func(int,int); // Declare a function (function prototype)
}
int main()
{
func(int a, int b); // Calling function . . .
return 0;
}
// Function definition . . .
void func(int m, int n)
{
//
//
}