9

私が知っているように、呼び出し規約はコンパイラとアーキテクチャに依存します。しかし、C と C++ の呼び出し規則の間に明確な違いはありますか?

4

5 に答える 5

11

しかし、C と C++ の呼び出し規則の間に明確な違いはありますか?

一般的に、何もありません。C++ は、可能な限り C と互換性を持つように意図的に設計されており、特に、すべてのシステムで C アプリケーション バイナリ インターフェイスを使用しています。

しかし、C ABI は C++ が必要とする多くの機能 (特に、オーバーロード、名前空間、関数テンプレート) に対応していないため、C++ コンパイラは関数の名前にいくつかの変更を加えます。これはネームマングリングと呼ばれます

したがって、C と C++ コードの間の関数呼び出しが機能するためには、そのような関数は、extern "C"名前マングリングを無効にし、呼び出し規則が C で期待されるものであることを確認するように宣言する必要があります (ただし、この後者の側面は、標準ではこれを義務付けていません)。

C++ には、C には存在しないメンバー関数 ( thiscallと呼ばれることもある) の追加の呼び出し規則もあります。ただし、フリー関数は、C と同じ呼び出し規則を使用します。

于 2012-06-29T07:01:24.830 に答える
7

どちらの標準にも、特定のコンパイラでCとC ++の呼び出し規約が同じである必要があるものはありません。ただし、宣言されたC ++関数はextern "C"、C関数と同じ呼び出し規約で呼び出す必要があります。

そのため、同じパラメーターと戻りタイプを持つ関数へのポインターとCリンクを使用した関数へのポインターのタイプは異なります。関数が呼び出されると、コンパイラは、関数が異なる場合、どの呼び出し規約で関数を呼び出すかを型から知ることができます。

実際には、Cリンケージがある場合とない場合のフリー関数間で互換性のない呼び出し規約を使用する例を故意に扱ったことはないと思います。通常、C ++実装は、実行を計画しているシステムのABIからの呼び出し規約を採用して、システムの他のユーザーがABIに関して理解できるリンク可能なオブジェクト(実行可能ファイルとライブラリ)を生成します。

これは必須ではありません。標準では、システムABIがあるかどうかは関係ありません。また、システムは通常、自己完結型の実行可能ファイル[*]内での呼び出し方法を気にしません。特別な理由がない限り、それを行うのは賢明です。特定のシステムのシステムABIは、C ++について言及している場合と言及していない場合があります。そうでない場合、非Cリンケージ関数に関する限り、C ++実装はそれ自体ですが、私が言うように、通常 Cリンケージを使用する場合は、Cリンケージを使用する場合と同じ呼び出し規約を使用します。

もちろん、Cの呼び出し規約には記載されていないものの、C ++の呼び出し規約で指定する必要があるものがあるため、「異なる」ではなく「互換性がない」と言います。たとえば、メンバー関数へのポインタを渡す方法。これはシステムABIによって固定されていない可能性があるため、C++の実装に任されています。この理由は、システムABIが、製造元がC ++コンパイラライターの仕事であると見なす処理を実行するのではなく、メンバー関数へのポインターの実装をC++実装に任せるためです。

呼び出し規約が邪魔にならないように、名前マングリングは、Cリンケージがある場合とない場合のフリー関数間で必然的に異なることに注意してください。その理由は、C ++の名前マングリングにはパラメーターのタイプを含める必要があるのに対し(関数のオーバーロードのため)、Cの名前マングリングにはパラメーターのタイプを含める必要がないためです(パラメーターが指定されていないextern関数宣言のため)。

[*]「間違った」呼び出し規約を使用すると、問題が発生する例を見てきましたが。ISTR Windowsモバイルデバイス。OSが予期したものとは異なる方法でスタックをフォーマットした場合、OSが問題のあるスレッドのスタックを再トレースしようとしたができなかったため、特定のハードウェア例外によってデバイスが削除されました。したがって、少なくともそのOSバージョンでは、おそらく2005年頃に、OSの診断を機能させたい場合は、Windowsの呼び出し規約を内部で使用する必要がありました。またはとにかく、スタックフレーム形式に関連する呼び出し規約の一部。もちろん、これは完全に私たちの失敗でしたが、最初から例外を発生させないことで回避するのではなく、ハードウェア例外用の独自のハンドラーをインストールすることで適切に修正できたかどうかはわかりません。ただし、ユーザーモードプロセスではスタックオーバーランによってOSが簡単にダウンする可能性があり、他のWindowsよりもコードのデバッグが困難であるということも意味していました。そのため、OSを少し非難しました。

于 2012-06-29T08:53:38.387 に答える
4

私が知っているように、呼び出し規約はコンパイラとアーキテクチャに依存します。

はい。

しかし、CとC ++の呼び出し規約の間に明確な違いはありますか?

より良い質問は「類似点はありますか?」です。

はい:

C ++アプリケーション内で宣言extern "C"された関数には、そのアーキテクチャーのC関数で使用されるのと同じ呼び出し規約があります。

呼び出し規約について行うその他の仮定は推測であり、同じである可能性がありますが、ケースバイケースでそれについて心配する必要があります。

于 2012-06-29T07:36:16.100 に答える
3

言語間で呼び出し規約を変えるという概念全体は、特定の言語 (およびその仕様) を超えています。そのようなことは、その名前に値する言語の仕様には関係ありません。基本的に、その通りです。それは、仕様の特定の実装、つまりコンパイラ アーキテクチャのドメイン内にあります。確かに、リンケージ仕様のような特定の言語の仕様/標準で議論されているいくつかの概念は、呼び出し規約に影響を与える可能性がありますが、それは計画された結果ではありません.

ABI の義務は、そのような概念を標準化/形式化することですが、これもまた、人々が尊重する義務はありません (実装のカラフルなパレットがかなり異なるため)。

本当に、仕様はパラメータがどのように渡されるか、スタックやレジスタ、両方の組み合わせ、割り当ての順序などを無視する必要があります。それは、実装に取り​​組んでいる人たちと設計する人々の仕事です実際のハードウェア、さらに重要なのは命令セットです。

したがって、標準化されている C も C++ も、実装方法について発言権を持っていません。したがって、言語固有の違いがあってはなりません。それらが適用される方法でのみ。それがコンパイラ アーキテクチャの分野です。

于 2012-06-29T07:25:22.853 に答える