CがC ++で不十分な言語の「バインディング」を提供するのはなぜですか?


60

私は最近、C ++を介してCを使用するタイミングを疑問に思っていました。幸いなことに、誰かがすでに私にそれ打ち負かし、しばらくかかりましたが、私はその質問に対するすべての答えとコメントを消化することができました。

ただし、その投稿の1つの項目は、検証や説明のような例なしで、何度も何度も対処されます。

「Cコードは、ライブラリに複数の言語バインディングが必要な場合に適しています」

それは言い換えです。複数の人がC ++で(いくつかのextern機能を介して)複数の言語バインディングが可能であることを指摘していることに注意する必要がありますが、それでも、その記事全体を読むと、Cが移植性/言語バインディングに理想的であることは明らかです。私の質問は:なぜですか?

Cでライブラリを記述すると他の言語でのバインディングや移植性が向上する理由を具体的に説明してください。


6
主に歴史的および社会的な理由のため。ほとんどの言語実装とランタイムシステムはCの上に構築されています。たとえば、Ocaml、SBCL、HaskellランタイムはCでコーディングされています(C ++で再コーディングしてもあまり得られません)
Basile Starynkevitch

8
実際には、これらのランタイムに本物のC ++ライブラリ(Qtのようなもの)を接着するのは苦痛です。
バジルスタリンケビッチ

3
@Basile:Qtは本物のC ++ライブラリではありません。また、より苦痛の多いライブラリであっても、実際に有用なセマンティクスを表現するため、苦痛を感じるだけです。
DeadMG


2
Don BoxによるEssential COMを読んでください。C ++でABIを作成するプロセスについて説明します。COMは、ABIを作成するマイクロソフトの方法でした。すなわち、COM C ++ライブラリはCまたはVBまたは他の言語から使用できます。
user93353

回答:


69

Cにははるかに単純なインターフェイスがあり、ソースコードインターフェイスをバイナリインターフェイスに変換するためのルールは簡単で、バインドする外部インターフェイスの生成は十分に確立された方法で行われます。一方、C ++は非常に複雑なインターフェイスを備えており、ABIバインディングのルールは、正式にも実際にも標準化されていません。つまり、どのプラットフォームのどの言語のコンパイラでも、外部Cインターフェイスにバインドして、何を期待すべきかを正確に知ることができますが、C ++インターフェイスの場合、ルールはコンパイラ、バージョン、およびバージョンによって変わるため、本質的に不可能ですC ++コードが構築されたプラットフォーム。

Cには、標準のバイナリ言語実装規則もありませんが、桁違いに単純であり、実際にはコンパイラは同じ規則を使用します。C ++コードのデバッグを難しくするもう1つの理由は、上記の複雑な文法です。これは、デバッガーが多くの言語機能を処理できないことが多いためです(ブレークポイントをテンプレートに配置する、ポインター表示コマンドをデータ表示ウィンドウに解析するなど)。

標準のABI(アプリケーションバイナリインターフェイス)の欠如には別の結果があります-同じツールとビルドオプションでコンパイルしないとユーザーコードが機能しないため、C ++インターフェイスを他のチーム/顧客に出荷するのは実用的ではありません。すでにこの問題の別の原因を見てきました-コンパイル時のカプセル化の欠如によるバイナリインターフェイスの不安定性です。

- 欠陥のあるC ++


4
あなたは(これはC ++で実装C-のようなAPIを定義することは可能であるが、ことに注意すべきであるextern "C"C ++で提供される機能とのバランスすべきことは、まだそうする複数の付加的な仕事である)
jhominal

5
C ++ ABIは、C ++ライブラリをで簡単にエクスポートできる質問のコンテキストでは無関係extern "C"です。
DeadMG

12
@jhominal:Cインターフェイスを定義する必要があり、Cで実装する必要があるCで記述するよりもはるかに優れていますが、C ++ではCインターフェイスを定義でき、実装する必要はありません実装する言語に関係なく、Cインターフェイスを定義する必要があります。これは、CまたはCバインディングを公開できる他の言語と同様に、C ++でも当然です。
-DeadMG

9
そのFQAドライブへのリンクに免責事項を追加することは可能でしょうか?
マーティンBa

2
@DocBrown:確かに質問はC言語バインディングとC ++言語バインディングに関する質問のようです。
メイソンウィーラー

32

別の言語の話者と通信しようとしている場合、ピジンはシェークスピア英語よりも簡単です。

Cの概念(関数呼び出し、ポインター、NULL終了文字列)は非常に単純なので、他の言語ではC関数を呼び出すのに十分なほど簡単に実装できます。歴史的な理由から、他の多くの言語がCで実装されているため、C関数をさらに簡単に呼び出すことができます。

C ++は、継承、vtable、およびアクセス修飾子を含むクラス-かなりのものを追加します。例外。スタックの巻き戻しと制御フローの変更。テンプレート。これにより、他の言語がC ++バインディングを使用するのが難しくなります。せいぜい、実装する「接着剤」または相互運用性コードが多く、最悪の場合、概念は直接変換されません(クラスモデルの違い、例外処理、等。)。特にテンプレートの場合、単純にテンプレートを使用(インスタンス化)するには、通常、C ++コンパイラを使用したコンパイル手順が必要であり、他の環境からテンプレートを使用するのは非常に複雑です。

以上のことから、C ++ライブラリから別の言語へのバインディングを提供することの難しさを誇張することができます。

  • C ++バインディングは、Cと同じように互換性があります。@DeadMGが指摘しているように、C ++はをサポートしているextern "C"ため、C ++ライブラリからCスタイルの言語バインディング(Cバインディングの単純さと互換性のすべてを含む)をエクスポートできます(C ++固有の機能を公開できないという制限があります) 。
  • C ++言語バインディングに対するもう1つの一般的な反対意見は、C ++のABI安定性の欠如ですが、これも誇張されています。C ++のABIはCのABI未満標準化されていますが、規格やデファクトスタンダードは(も使用されているItaniumのC ++ ABI、存在しませんOS X上でGCCのデファクトスタンダード Linux用)を。Windowsはさらに悪いですが、Windowsでも、Visual C ++の1つのバージョンにとどまることで問題なく動作するはずです。

1
C ++ライブラリから別の言語へのバインディングを提供することに関する他の問題は、他の言語がバインディングをCで実装することを必要とする可能性があることです。または、(。C ++ ABI を使用するためのツールを提供しない場合があります。
Random832

6
@ Random832:C ++側が単にCインターフェースを提供できる場合、これは完全に無関係です。Cバインディングを提供するためにCでバインディングを実装する必要はありません。
-DeadMG

21

Cは、現在でも最も古い言語の1つです。ABIはシンプルで、現在も使用されているほぼすべてのオペレーティングシステムが記述されています。これらのOSの一部は、たとえばC#/。NETまたはその上にあるものを追加しているかもしれませんが、その下には非常にCに浸っています。

つまり、OSが提供する機能を使用するために事実上すべてのプログラミング言語にCライブラリとのインターフェースが必要でした。Perl、Java、C ++、それらはすべて、ネイティブに「Cを話す」方法を提供します。なぜなら、すべての車輪を再発明したくない場合に必要だったからです。

これにより、Cはプログラミング言語のラテン語になります。(その比phorが「プログラミング言語の英語」でなければならないまでのインターネットの長さは?)


ライブラリをCで作成すると、C互換のインターフェイスが無料で得られます(明らかに)。ライブラリをC ++で記述している場合、前述の宣言を介してCバインディング取得できextern "C"ます。

ただし、これらのバインディングは、Cで表現できる機能に対してのみ取得できます

したがって、ライブラリAPIは使用できません...

  • テンプレート、
  • クラス、
  • 例外、
  • オブジェクトを取得または返す関数。

簡単な例の1つとして、エクスポートされた関数に配列()の代わりに(およびその点で)を取得させ返す必要があります。[]std::vectorstd::string

そのため、C ++がライブラリのクライアントに提供する優れた機能を提供できないだけでなく、ライブラリAPIをC ++から「C互換」に「変換」するための追加努力も必要になります(extern "C")。

これが、Cがライブラリを実装するためのより良い選択であるということを指摘できる理由です。個人的には、C ++の利点はextern "C"APIに必要な労力を上回っていると思いますが、それは私だけです。


Windowsは.NETをベースにしようとしているようです。AndroidはJava(一部の APIの実装の詳細としてもC)をベースにしています。iOS/ OSXはObjective-Cをベースにしています。
user253751

1
英語はすでにプログラミングの世界で主要な言語です。他の職業よりも支配的。
思源レン

3
@immibis:Windows、Linux / Android、およびBSD / OSXはすべてCで書かれたカーネルであり、インターフェースはCで書かれています(そしてCで書かれています)。 NETにはC呼び出し、PythonにはC呼び出し、Objective-CにはC呼び出しが必要です。それらのどれも、C ++呼び出しを必要としません。
DevSolar

@DevSolar Androidの多くはJavaでネイティブに記述されており、JNIを使​​用しません(CからJavaコードを呼び出すために「後方」に使用できますが、それはネイティブJavaであることをさらに確認します)。iOS / OSXの経験はありませんが、Objective-Cでも同じだと聞きました。
user253751

3
@immibis:しかし、あなたがやるあなたは、OSのカーネルとそのユーザー空間の違いを知らないのか?私は、ほとんどJavaのユーザー空間が、Androidをデスクトップ上で実行しているLinuxカーネルよりもCスタイルのシステムコールを備えたLinuxカーネルにすることを真剣に疑っています。また、カーネルやミドルウェアでJavaを使用しているのではないかと疑っています。実際、彼らはそこでCを使用していることを知っています。それは鶏卵問題であり、逆の問題です。それは前にCで行われていますので、それがためにとても簡単です、まだ C.でそれを行う
DevSolar

6

他の回答がすでに提供している詳細を省きます:

多くの言語がCバインディングを提供する理由は、すべての* nixおよびWindowsオペレーティングシステムがCインターフェイスを介してOS APIのほとんどを公開するためです。そのため、主要なOsesで実行できるように、言語実装はすでにCとのインターフェースをとる必要があります。したがって、言語自体から任意のCインターフェイスとの直接通信を提供することも簡単です。


5

理由はありません。あなたが表現しようとしているセマンティクスは基本的にCと互換性のないテンプレートのようなものであれば、実装は実際にはCで書かれている場合は、簡単にバインドすることができない理由は、それはかなりのだ、存在しない定義によって Cインタフェースが可能別の言語での実装を含む、バイナリ契約を満たすことができる任意の実装によって記入されます。この方法で動作できるCバイナリコントラクトを実装できるC ++以外の言語があります。

要するに、恐竜時代にとどまる理由を必死に選んで、実際に役立つセマンティクスや機能を備えた新しい言語やアイデアを学びたくない人たちです。


4
私はあなたが正しいと思い、ダウンボッターは質問を誤解していましたが、実際にはあなたの答えは潜在的な誤解を強調するために見落としていました。 「完全にCで記述されたライブラリ」対「C ++で記述されたCインターフェイスを備えたライブラリ」。
ドク・ブラウン

@Snowman:問題のあるC ++バインディングは、Cバインディングの公開に関する問題とはまったく関係ありません。
-DeadMG

2
それでは、有用なセマンティクスと機能を備えた言語を選択し、それらをCインターフェイスに強制的に変換するのでしょうか。クラスとテンプレートは回避可能かもしれませんが(最初にC ++を使用する理由を疑問視します)、Cバインディングを使用するすべての関数は、Cコードにエスケープするのではなく、例外をキャッチする必要があります。言うまでもなく、C互換ライブラリを使用するユーザーは、基板CのABIの衝突とライブラリの不一致に加えて、C ++とそのABIの衝突とライブラリの不一致に対処する必要があります。
-prosfilaes

2
@prosfilaes:例外をリターンコードに変換するのは簡単です。クラスはC APIに簡単に下げることができるため、クラスの使用を避ける必要はありません。また、実装でテンプレートの使用を避ける必要はありません。また、ソースからビルドしている場合を除き、ユーザーはC ++ ABIの衝突についてたわごとをする必要はありません。
-DeadMG

4
C ++でC APIを使用してライブラリを作成する必要は必ずしもないのではなく、恐竜であることに加えてCを使用する十分な理由があるため、私はダウン票を投じました。言語XでAPIを作成する場合、C、FORTRAN、COBOL、BLISS、またはJavaである場合、その言語で記述し、より洗練されたもので記述する方が、より簡単で、簡単で、より正確になります、より楽しい言語と2つのインターフェイス。
prosfilaes

2

別の言語とインターフェイスする場合、2つの主要な軸があります。

  • インターフェースが引き継ぐことができる概念:値だけ?参照?ジェネリック?
  • インターフェイスが「バイナリ」(ABIと呼ばれる)でどのように実装されるか

Cは、これらの2つの面でC ++よりも優れています。

  • Cには、他のほとんどすべての言語に現れる単純な概念しかありません1
  • CバイナリのABIはOS 2によって決定されます

さて、なぜほとんどの言語がCと同じような概念のセットを持っているのは、それが「単純」または「既存」であるためかもしれません。しかし、それは問題ではありません、ポイントは彼らがするということです。

それどころか、C ++には複雑な概念があり、ABIは各コンパイラによって決定されます(ただし、Windowsを除き、多くはItanimum ABIに準拠しています)。この問題を部分的に解決するために、OSにC ++ ABIを(OSごとに)修正するというHerb Sutterの提案が実際にありました。また、C ++ FFIが可能であることに注意する必要があります。Dはそれを試みています3

1バリアド(...)を除き、それらは単純ではありません

2 Cには標準のABIがありますか?

3 DとレガシーC ++コードのインターフェース


0

基本的には、ABIの標準化に基づいています。CもC ++も、他の言語が書かれたバイナリ間のインターフェースに使用できる標準化されたABIを持たないが、Cは事実上の標準になり、誰もがそれを知っており、誰もが言語に関して持っている同じ、シンプルなルールを使用できる型と関数呼び出し。

C ++は標準のABIを使用できますが、Stroustrupは、ABIの必要性はないと述べています。また、コンパイラライターからコンセンサスを得るのは難しいだろうと言います(ただし、C ++標準委員会は既存のものと同様のABIを発行し、コンパイラライターはコンパイラの次のバージョンを変更するだけであり、バイナリと互換性がない場合があります)とにかく古いバージョンのコンパイラで構築された-いくつかのライブラリを新しいSunコンパイラで再コンパイルし、古いライブラリで動作しなかったことがわかりました)

一部の企業は標準のABIを使用するようになったことに注意してください。Microsoftは90年代にCOMでこのプロセスを開始し、今日ではこれをWinRT ABIに改良しました(他のWinRTと混同しないでください) C#で記述されたプログラムがCまたはC ++で記述されたライブラリと通信できるようにするタイプのテーブルOS)

標準化団体が立ち上がってこの状況を修正しない限り、誰もできることはあまりありません。マイクロソフトは明らかにその価値を認識しており、プラットフォームでそれを解決するための手段を講じています。

そのため、実際にはC 言語バインディングを提供していません。誰も聞いていないにもかかわらず、それらを消費します。


-2

すべての答えは本当の問題には至りません。C++コンパイルは「名前のマングリング」を導入するため、バイナリは「単純な」関数呼び出しと互換性がありません。

ABIのものはすべて、標準化の試みにすぎません。

一般に、プレーンなC ++に固執していても、異なるコンパイラでコンパイルされた関数をクロスリンクできることは保証されていません。以前は互換性がないと確信していましたが、今日では標準化が忍び込んでいます;)

OTOH Cは、「高レベルのアセンブリ」として正確に設計され、あらゆる種類の簡単なインターフェースを可能にします。言語間の好みにより適していることは驚くべきことではありません。

サイドノート:オリジナルのC ++コンパイラ(cfront)は、実際にコンパイルする必要のあるCソースを生成しました。これは、「フードの下で」アセンブリを生成するgccとまったく同じです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.