1. ホーム
  2. c++

[解決済み] C++とCの融合 - #ifdef __cplusplus はどのように機能するのか?

2022-02-14 07:17:28

質問

レガシーが多いプロジェクトに携わっています。 C のコードです。 私たちはC++で書き始めましたが、最終的にはレガシーコードも変換するつもりです。 がどのように変換されるのか、少し混乱しています。 C とC++の相互作用について教えてください。 をラップすることで C のコードを extern "C" C++ コンパイラは C のコードの名前をどう実装すればいいのか、全く分からない。

そこで、それぞれの C ヘッダーファイル(インクルードガードの後)には

#ifdef __cplusplus
extern "C" {
#endif

と書き、一番下には

#ifdef __cplusplus
}
#endif

この2つの間に、include、typedef、関数のプロトタイプをすべて配置します。 私がこのことを正しく理解しているかどうか、いくつか質問があります。

  1. C++のファイルA.hhがあるとして、それが を含んでいます。 C ヘッダーファイル B.h, は別の C ヘッダーファイル C.h, はどのように動作するのでしょうか? 私が思うに コンパイラがB.hに踏み込むと __cplusplus が定義されているので で囲みます。 extern "C" (そして __cplusplus にはなりません。 このブロックの内部で定義されます)。 だから に踏み込むと、C.h, __cplusplus は定義されません。 でラップされることはありません。 extern "C" . これは正しいのでしょうか?

  2. を使用することに何か問題があるのでしょうか? でラップする。 extern "C" { extern "C" { .. } } ? 2つ目の extern "C" はどうする?

  3. このラッパーは.cファイルには付けず、.hファイルだけに付けます。 では、関数にプロトタイプがない場合はどうなるのでしょうか?コンパイラはそれをC++の関数だと思うのでしょうか?

  4. また、サードパーティの で書かれたコードです。 C であり このようなラッパーはありません。 となります。 ヘッダをインクルードするときは常に そのライブラリから は extern "C" を#includeで囲んでいます。 これは正しい対処法でしょうか? ということでしょうか?

  5. 最後に、この設定で良いのでしょうか? 他にやるべきことはありますか? これからミキシングするのは C とC++の この先もずっとそうであるように、私は をカバーできるようにしたい。 ということです。

解決方法は?

extern "C" は、コンパイラがコードを読み取る方法を変えるものではありません。 コードが .c ファイルにあれば C としてコンパイルされ、.cpp ファイルにあれば C++ としてコンパイルされます (設定に何か変なことをしない限り)。

extern "C" は、リンクに影響を与えます。 C++の関数は、コンパイルされるときに、その名前が変形されます。 関数名はパラメータの型と数に基づいて変更されるため、同じ名前の2つの関数は異なるシンボル名を持つことになります。

の中のコードは extern "C" はC++のコードのままです。 extern "C"ブロックの中でできることには制限がありますが、それはすべてリンクに関するものです。 Cのリンクで構築できない新しいシンボルを定義することはできません。 つまり、例えばクラスやテンプレートはダメということです。

extern "C" ブロックがうまくネストしています。 また extern "C++" の中に閉じ込められ、どうしようもなくなってしまった場合。 extern "C" リージョンは、クリーンルームの観点からはあまり良いアイデアではありません。

では、具体的に番号のついた質問について。

1について: __cplusplusは、以下の内部で定義されたままです。 extern "C" ブロックを使用します。 しかし、ブロックはきちんとネストされるべきなので、これは重要ではありません。

2について: __cplusplusは、C++コンパイラを通して実行されているすべてのコンパイル単位で定義されます。 一般的に、それは.cppファイルと、その.cppファイルによってインクルードされるすべてのファイルを意味します。 同じ .h (または .hh や .hpp など) が、異なるコンパイル単位に含まれる場合、異なる時点で C または C++ として解釈される可能性があります。 もし、.hファイルのプロトタイプがCのシンボル名を参照するようにしたい場合は、プロトタイプに extern "C" は、C++として解釈されるときには extern "C" として解釈されます。 #ifdef __cplusplus をチェックします。

質問の答えその3:プロトタイプを持たない関数は、.cppファイル内で extern "C" ブロックがあります。 なぜなら、プロトタイプを持たない関数は、同じファイル内の他の関数からしか呼び出されないからです。

4については、まさにその通りです。 もしあなたがCリンケージを持つコード(例えばCコンパイラでコンパイルされたコード)のヘッダをインクルードしているなら、次のようにしなければなりません。 extern "C" そうすれば、そのライブラリとリンクすることができます。 (そうすれば、ライブラリとリンクすることができます(そうしないと、リンカは _Z1hic を探しているときに void h(int, char)

5: このような混在は、一般的な理由で extern "C" そして、この方法で行うことは何も悪いことだとは思いません。