このリンクを見ましたが、「extern」を使用したコードのパフォーマンスの低下を求めていません。 「extern」がないということですが、C++でCライブラリを使用するときに「コンテキスト切り替え」はありますか? C++アプリケーションで純粋なC(クラスラップされていない)関数を使用するときに問題はありますか?
CとC++はどちらもプログラミング言語仕様(英語で書かれています。C11の仕様については n157 などを参照)であり、パフォーマンスについては話しません(プログラムの動作、つまり semantics )について。
ただし、 [〜#〜] gcc [〜#〜] や Clang などのコンパイラを使用する可能性があります。これらのコンパイラはビルドされるため、パフォーマンスが低下することはありません。 C言語とC++言語の両方で、同じ種類の中間内部表現(GCCの場合はGIMPLE、Clangの場合はLLVMなど)。CおよびC++コードは互換性があるため [〜#〜] abi [〜#〜] = sおよび 呼び出し規則 。
実際には、extern "C"
は呼び出し規約を変更しませんが、 名前マングリング を無効にします。ただし、コンパイラへの正確な影響は、そのコンパイラに固有です。 インライン化 を無効にする(または無効にする)場合があります(ただし、GCCでのリンク時間の最適化には-flto
を検討してください)。
一部のCコンパイラ(例: tinycc )は、パフォーマンスの低いコードを生成します。 [〜#〜] gcc [〜#〜] または Clang でさえ、-O0
とともに使用する場合、またはを明示的に使用しない場合有効化 最適化 (例: passing-O1
または-O2
など)は、スローコードを生成する可能性があります(最適化はデフォルトで無効になっていますそれ)。
ところで、C++はCと相互運用できるように設計されています(そして、その強い制約がC++のほとんどの欠点を説明しています)。
場合によっては、正規のC++コードは、対応する正規のCコードよりもわずかに高速である可能性があります。たとえば、数値の配列を並べ替えるには、正規のC++では std :: array および std :: sort を使用し、並べ替えの比較操作は可能性があります。インライン化する。 Cコードでは、 qsort を使用するだけで、各比較は間接的な関数呼び出しを通過します(理論的には可能であっても、コンパイラーがqsort
をインライン化しないため...) 。
他のいくつかのケースでは、本物のC++コードはわずかに遅くなる可能性があります。たとえば、::operator new
のいくつかの(すべてではない)実装は、単にmalloc
を呼び出していますが(失敗をチェックしています)、インライン化されていません。
実際には、呼び出し規約には互換性があるため、C++コードからCコードを呼び出したりCコードからC++コードを呼び出したりしてもペナルティはありません。
C longjmp 機能は、おそらくC++例外をスローするよりも高速ですが、同じセマンティクスを持っておらず( stack unwinding を参照)、longjmp
はそうではありません。 C++コード全体でよく混ぜます。
パフォーマンスをそれほど気にする場合は、コードとベンチマークを2倍(正規のCと正規のC++で)記述します。 CとC++の間で小さな変化(最大で数パーセント)が見られる可能性が高いので、私はまったく気にしません(そしてあなたのパフォーマンスの懸念実質的に不当です)。
コンテキストスイッチ は オペレーティングシステム および マルチタスク に関連する概念であり、 プロセス 実行中 マシンコード 実行可能 プリエンプション 。 実行可能 がどのように取得されるか(Cコンパイラ、C++コンパイラ、Goコンパイラ、SBCLコンパイラ、またはPerlやバイトコードPythonなどの他の言語のインタプリタであること)はまったく関係ありません。 (コンテキスト切り替えは、任意のmachine命令で、 interrupts の間に発生する可能性があるため)。 オペレーティングシステム:3つの簡単なピース のような本を読んでください。
基本レベルnoでは、C++コードからCライブラリを呼び出すときに、パフォーマンスの「切り替え」によるペナルティは発生しません。たとえば、C++から別の変換ユニットで定義されたCメソッドを呼び出すと、別の変換ユニットでC++に実装された同じメソッドを(同じCのように)呼び出すのとほぼ同じパフォーマンスが得られます。
これは、CおよびC++コンパイラの一般的な実装が最終的にソースをネイティブコードにコンパイルし、extern "C"
関数の呼び出しが、C++呼び出しで発生する可能性のある同じタイプのcall
を使用して効率的にサポートされるためです。呼び出し規約は通常、プラットフォームABIに基づいており、どちらの場合も同様です。
その基本的な事実はさておき、C++で同じ関数を実装するのとは対照的に、C関数を呼び出すとパフォーマンスが低下する可能性があります。
extern "C"
で宣言され、C++コードから呼び出される関数は、通常、インライン化されません(定義上、ヘッダーに実装されていないため)。これにより、ホスト全体が非常に強力な最適化を行うことができなくなります。。std::string
がある場合は、別のタイプを選択してCコードに渡す必要があります-char *
が一般的ですただし、明示的な長さに関する情報は失われます。これは、C++ソリューションよりも遅い場合があります。多くのタイプには直接Cに相当するものがないため、コストのかかる変換で立ち往生する可能性があります。malloc
とfree
を使用しますが、C++コードは通常new
とdelete
を使用します(通常、これらの呼び出しを他のクラスの背後に隠すことを好みますできるだけ)。他の言語で解放されるメモリを1つの言語で割り当てる必要がある場合、これにより、解放を行うために「他の」言語にコールバックする必要がある不一致が発生したり、不要なコピーが発生したりする可能性があります。上記の懸念は、純粋なC++実装とC実装を対比する場合にのみ当てはまり、Cを呼び出すときにパフォーマンスが低下することを意味するわけではありません。「CとCを組み合わせてアプリケーションを作成できるのはなぜですか」という質問に答えています。 C++は純粋なC++よりも遅いですか?」さらに、上記の問題は主に、上記のオーバーヘッドが重要になる可能性がある非常に短い呼び出しの懸念事項です。 Cで長い関数を呼び出す場合は、それほど問題にはなりません。 「データ型の不一致」はまだあなたを悩ますかもしれませんが、これはC++側で設計することができます。
興味深いことに、リンク時の最適化により、実際にはCメソッドを C++コードにインライン化 にすることができます。これは、LTOのほとんど言及されていない利点です。もちろん、これは通常、適切なLTOオプションを使用してソースからCライブラリを自分で構築することに依存しています。
1 たとえば、標準のレイアウトタイプ以外のほとんどすべてのもの。
2 これは、多くのC++標準ライブラリ呼び出しが、std::copy
がmemcpy
またはmemset
を呼び出す方法など、最終的に「重い」リフティングのためにCライブラリルーチンに委任するという事実によって少なくとも部分的に軽減されます。可能な場合、およびほとんどのnew
実装が最終的にmalloc
を呼び出す方法。
C++は当初から大きく成長し、変更されましたが、設計上、Cとの下位互換性があります。C++コンパイラは通常Cコンパイラから構築されますが、 リンク時の最適化 でさらに近代化されます。多くのソフトウェアが、ユーザースペースと使用されるライブラリの両方でCコードとC++コードを確実に組み合わせることができると思います。 最近質問に答えました C++クラスのメンバー関数ポインタをCで実装されたライブラリ関数に渡す必要がありました。ポスターはそれが彼のために働いたと言った。したがって、C++はプログラマーやユーザーが考えるよりもCとの互換性が高い可能性があります。
ただし、C++は、オブジェクト指向であるためCが機能しない多くの異なるパラダイムで機能し、抽象化、新しいデータ型、および演算子の全範囲を実装します。特定のデータ型は簡単に翻訳できます(char *
C文字列からstd::string
)、他の人はそうではありませんが。 C++コンパイラオプションに関するGNU.orgのこのセクション 興味深いかもしれません。
2つの言語を混在させても、パフォーマンスの低下についてあまり心配したり心配したりすることはありません。エンドユーザー、そしてプログラマーでさえ、データの大きな抽象化を扱っていない限り、パフォーマンスの測定可能な変化にほとんど気付かないでしょう。