web-dev-qa-db-ja.com

extern "C"を簡単な言葉で使用するのはいつですか?

CとC++の違いがわからないかもしれませんが、いつ、なぜ使用する必要があるのでしょうか。

extern "C" {

?どうやらそれは「リンケージコンベンション」です。

それについて簡単に読んだところ、MSVSに含まれているすべての.hヘッダーファイルがコードを囲んでいることに気付きました。 「C++コード」ではなく「Cコード」とは正確にはどのタイプのコードですか? C++にはすべてのCコードが含まれていると思いましたか?

これは当てはまらず、C++は異なり、標準の機能/関数はどちらか一方に存在しますが、両方には存在しないと思います(つまり、printfはCで、coutはC++です)が、C++は下位互換性があります。 extern「C」宣言。これは正しいです?

私の次の質問は最初の答えに依存しますが、とにかくここで尋ねます:Cで書かれたMSVSヘッダーファイルはextern "C" {...}で囲まれているので、いつこれを使用する必要がありますかあなた自身のコードであなた自身?コードがCコードであり、C++コンパイラでコンパイルしようとしている場合、含めるすべての標準hファイルにはC++コンパイラでextern "C"が既に含まれているため、問題なく動作するはずです。

C++でコンパイルするときにこれを使用する必要がありますが、すでに構築されているCライブラリなどにリンクしていますか?

26
Russel

Cで実装/コンパイルされた関数を宣言するときは、C++でextern "C"を使用する必要があります。extern "C"を使用すると、コンパイラ/リンカはC++名の代わりにCの命名規約と呼び出し規約を使用するようになります。それ以外の場合に使用されるマングリングおよびC++呼び出し規約。他のライブラリによって提供される関数の場合、extern "C"を使用する必要はほとんどありません。適切に作成されたライブラリには、CとC++の両方にエクスポートするパブリックAPI用にすでにこれが含まれています。ただし、CとC++の両方で使用できるようにするライブラリを作成する場合は、条件付きでそれをヘッダーに配置する必要があります。

すべてのCコードがC++コードであるかどうかについては...いいえ、それは正しくありません。 C++は「Cのスーパーセット」であるというのは一般的な神話です。 C++は確かに可能な限りCとの互換性を保つように努めていますが、いくつかの 非互換性 があります。例えば、 ブール は有効なC++ですが、有効なCではありません。 _Bool C99には存在しますが、C++では使用できません。

システムの「.h」ファイルでextern「C」を使用する必要があるかどうかについては、適切に設計された実装にはそれらが含まれているため、使用する必要はありません。ただし、それらが確実に提供されるようにするには、「c」で始まり「.h」を省略した同等のヘッダーファイルをインクルードする必要があります。たとえば、<ctype.h>を含めると、ほとんどすべての妥当なシステムに外部「C」が追加されます。ただし、C++互換のヘッダーを確保するには、代わりにヘッダー<cctype>を含める必要があります。

C++からCとC++を混合するFAQ Lite )にも興味があるかもしれません。

30

他の答えは正しいですが、完全な「ボイラープレート」の例がおそらく役立つでしょう。 Cおよび/またはC++プロジェクトにCコードを含めるための標準的な方法は次のとおりです。

//
// C_library.h
//

#ifdef __cplusplus
extern "C" {
#endif

//
// ... prototypes for C_library go here ...
//

#ifdef __cplusplus
}
#endif

-

//
// C_library.c
//

#include "C_library.h"

//
// ... implementations for C_library go here ...
//

-

//
// C++_code.cpp
//

#include "C_library.h"
#include "C++_code.h"

//
// ... C++_code implementation here may call C functions in C_library.c ...
//

注:上記は、Objective-C++からのCコードの呼び出しにも当てはまります。

17
Paul R

C++コンパイラは、Cコンパイラとは異なる方法でシンボルテーブル内の名前をマングルします。シンボルテーブルを作成するときに、代わりにCマングリング規則を使用するようにC++コンパイラに指示するには、extern "C"宣言を使用する必要があります。

'extern c'を使用して、C#がC++ dll関数のエクスポート時に行われる余分な名前マングリングを理解することなくC++コードを読み取れるようにします。それ以外の場合は、dll内のC++関数に適切にアクセスするために、C#側の関数エントリポイントの最後に追加する必要のある無意味な(または実際には英語以外の)文字があります。

2
mmr

extern "C" {}ブロックは、C++コンパイラにCの命名規則と呼び出し規約を使用するように指示します。これを使用しない場合、C++プロジェクトにCライブラリを含めようとすると、リンカーエラーが発生します。これは、C++が名前を壊してしまうためです。 C++プロジェクトで使用される場合に備えて、すべてのCヘッダーでこれを使用する傾向があります。

#ifdef __cplusplus
extern "C" {
#endif

/* My library header */

#ifdef __cplusplus
} // extern
#endif
2
Mike Weller

C++コンパイラでコンパイルされたコードでC呼び出し規約を使用する場合は、extern "C"を使用する必要があります。これには2つの理由があります。

  • Cで実装された関数があり、それをC++から呼び出したいとします。

  • C++で実装された関数があり、それをCから呼び出したい場合。この場合、関数インターフェイスではC++のC部分のみを使用できることに注意してください(クラスなどはありません)。

これは、Cとは別に、C++とCと同じ呼び出し規則および命名規則を使用する他の言語との間で相互運用する場合にも当てはまります。

通常、Cヘッダーファイルの宣言はで囲まれています

#ifdef __cplusplus
extern "C" {
#endif

[... C declarations ...]

#ifdef __cplusplus
}
#endif

c ++から使用できるようにします。

2
starblue

C++関数は 名前マングリング の対象となります。これにより、extern "C"を使用しない限り、Cコードから直接呼び出すことはできません。

0
Nathan Osman