議論から どこか別の場所 :
C++には標準のABIがありません
しかし、Cもそうではありませんか?
どのプラットフォームでも、ほとんどそうです。言語間コミュニケーションの共通語がなければ、それは有用ではありません。
これについてどう思いますか?
CはABIを定義しません。実際、ABIの定義を回避するために、後方に曲がっています。私のように、プログラミングのほとんどを8ビットバイトの16/32/64ビットアーキテクチャでCでプログラミングし、2の補数演算とフラットアドレス空間を使用している人々は、通常、次の複雑な言語を読んで非常に驚かれることでしょう。現在のC標準。
たとえば、ポインタに関するものを読んでください。この規格では、「ポインタはアドレスである」という単純なことは何も述べていません。そのため、ABIについての仮定が立てられます。特に、ポインタが異なるアドレス空間にあり、幅が異なる場合があります。
ABIは、言語の実行モデルから特定のマシン/オペレーティングシステム/コンパイラの組み合わせへのマッピングです。一部のアーキテクチャでC実装を除外するリスクがあるため、言語仕様で1つを定義することは意味がありません。
Cには原則として標準のABIはありませんが、実際には、これが問題になることはめったにありません。OSベンダーが行うことを実行します。
たとえば、x86 Windowsの呼び出し規約を見てください。WindowsAPIは、いわゆる「標準」呼び出し規約(stdcall)を使用します。したがって、OSとのインターフェースを希望するコンパイラーは、それを実装する必要があります。ただし、stdcallはすべてのC90言語機能をサポートしているわけではありません(たとえば、プロトタイプなしの関数の呼び出し、可変個引数関数)。 MicrosoftがCコンパイラを提供したため、「C」呼び出し規約(cdecl)と呼ばれる2番目の呼び出し規約が必要でした。 Windows上のほとんどのCコンパイラは、これをデフォルトの呼び出し規約として使用するため、相互運用可能です。
原則として、同じことがC++でも発生する可能性がありますが、C++ ABI(呼び出し規約を含む)は必然的にはるかに複雑であるため、コンパイラベンダーは単一のABIに同意しませんでしたが、extern "C"
にフォールバックすることで相互運用できました。
ABIには、Cの場合でも、プラットフォームにまったく依存しない部分、プロセッサに依存する部分(レジスタを保存する必要があり、パラメータの受け渡しに使用される部分など)、およびOSに依存する部分(多かれ少なかれ)があります。一部の選択はアーキテクチャによって課せられないが、トレードオフの結果であるため、プロセッサの場合と同じ要因に加えて、一部のOSには言語に依存しない例外の概念があるため、任意の言語のコンパイラは適切な処理を生成する必要がありますそれら、スレッドの処理もABIに何かを課す可能性があります-レジスタがTLSを指している場合、それを目的に使用することはできません)。
理論的には、すべてのコンパイラが独自のABIを持っている可能性があります。しかし、通常、カップルプロセッサ/ OSの場合、ABIはOSベンダーによって修正されます。OSベンダーは、ABIと競合他社が互換性を好むことを使用するCコンパイラと共通ライブラリも提供することがよくあります。 (Cが主要なプログラミング言語ではない一部のOSに例外があったとしても、私は驚かないでしょう)。
ただし、OSベンダーは何らかの理由でABIを切り替える場合があります(新しいバージョンのプロセッサには、ABIで使用したい機能がある場合があります-たとえば、すべてのレジスタを使用できるx86_64用の32ビットABIを要求する人もいます) 。移行フェーズでは(非常に長い時間がかかる場合があります)、2つのABIを処理する必要がある場合があります。
ABI for Cはプラットフォーム固有であり、レジスタ割り当てや呼び出し規約など、明らかに特定のプロセッサに固有の問題をカバーしています。ここではいくつかの例を示します。
x86には多くの呼び出し規約があり、Windowsではどの拡張機能を使用するかを宣言します。組み込みLinuxのプラットフォームABIも時間の経過とともに変化し、互換性のないユーザースペースにつながっています。 ARM Linuxポートはこちら の履歴を参照してください。これは、新しいABIへの移行における問題を示しています。
cもそうではありませんか?
正しい
どのプラットフォームでも、それはほぼです。言語間コミュニケーションの共通語がなければ、それは有用ではありません。
かなり多くは、他の言語に適合しているCコンパイラベンダーによって選択されたアーキテクチャ固有のデフォルトを指す場合があります。したがって、KeilのARM Cコンパイラが左から右のリトルエンディアンパラメータの順序とスタックを使用して引数と戻り値の所定のレジスタを渡す場合、他のコンパイラのextern "C"はそのようなものとの互換性を前提とします。スキーム。
このような合意はABIの一部と見なされる可能性がありますが、JVMブラウザーサンドボックスなどのマネージド実行コンテキストとは異なり、これだけでは完全な標準ABIとは言えません。
複数のオペレーティングシステム(特にUnixシステム上のi386)で、特定のアーキテクチャに対して単一のABIを定義する試みがいくつか行われていますが、そのような成功には至っていません。代わりに、オペレーティングシステムは独自のABIを定義する傾向があります...
引用... Linuxシステムプログラミング 4ページ。
Cには標準のABIがありません。これは、そこで使用されているすべての呼び出し規約(cdecl、fastcall、stdcall)によって簡単に説明されます。それぞれが異なるABIです。
C89標準より前は、多くのプラットフォームのCコンパイラは、データサイズの変動を除いて、基本的に同じABIを使用していました。スタックが下に大きくなるマシンの場合、関数を呼び出すコードは、スタック上の引数を右から左に順番にプッシュし、次に関数を呼び出します(プッシュプロセスのリターンアドレス)。呼び出された関数は引数をスタックに残し、呼び出し元は自由にスタックポインターを調整してそれらを削除します[または、一部のアーキテクチャでは、スタック値を所定の位置に調整する場合があります]。 <stdarg.h>
ほとんどのプログラムがその規則に依存する必要がなくなり、シンプルで非常にうまく機能したため、長年使用され続けました。クロスプラットフォームの「標準」としてそれを確立する「公式」ドキュメントはありませんでしたが、スタックが減少するマシンを対象とするほとんどのコンパイラはそのように機能し、現在よりも高いレベルの一貫性をもたらしました。