Mengapa C memberikan 'binding' bahasa di mana C ++ gagal?

60

Saya baru-baru ini bertanya-tanya kapan harus menggunakan C lebih dari C ++, dan sebaliknya? Untungnya seseorang sudah mengalahkan saya untuk itu dan meskipun butuh beberapa saat, saya bisa mencerna semua jawaban dan komentar untuk pertanyaan itu.

Namun satu item dalam posting itu terus ditangani berulang kali, tanpa ada contoh, verifikasi atau penjelasan:

"Kode C baik untuk ketika Anda ingin memiliki beberapa ikatan bahasa untuk perpustakaan Anda"

Itu parafrase. Saya harus mencatat bahwa beberapa orang menunjukkan bahwa binding beberapa bahasa dimungkinkan dalam C ++ (melalui beberapa externfungsi), namun demikian, jika Anda membaca posting itu secara keseluruhan, cukup jelas bahwa C sangat ideal untuk portabilitas / pengikatan bahasa. Pertanyaan saya adalah: mengapa?

Dapatkah seseorang tolong memberikan alasan konkret mengapa menulis perpustakaan di C memungkinkan untuk binding dan / atau portabilitas yang lebih mudah dalam bahasa lain?

smeeb
sumber
6
Sebagian besar karena alasan historis dan sosial. Sebagian besar implementasi bahasa dan sistem runtime dibangun di atas C. Misalnya, Ocaml, SBCL, Haskell runtime dikodekan dalam C (dan tidak akan mendapatkan banyak dengan dikodekan ulang dalam C ++)
Basile Starynkevitch
8
Dalam praktiknya, menempelkan pustaka C ++ asli (pikirkan Qt) ke dalam runtime ini menyakitkan.
Basile Starynkevitch
3
@Basile: Qt bukan pustaka C ++ asli. Juga, bahkan untuk perpustakaan yang lebih menyakitkan, itu hanya menyakitkan karena mereka mengekspresikan semantik yang sebenarnya berguna.
DeadMG
2
Baca Essential COM oleh Don Box. Ini menjelaskan proses membuat ABI di C ++. COM adalah cara Microsoft menciptakan ABI. yaitu pustaka COM C ++ dapat digunakan dari C atau VB atau bahasa lain.
user93353

Jawaban:

69

C memiliki antarmuka yang jauh lebih sederhana, dan aturannya untuk mengubah antarmuka kode sumber menjadi antarmuka biner cukup mudah sehingga menghasilkan antarmuka eksternal untuk diikat dilakukan dengan cara yang mapan. C ++, di sisi lain, memiliki antarmuka yang sangat rumit, dan aturan untuk pengikatan ABI sama sekali tidak standar, baik secara formal maupun dalam praktik. Ini berarti bahwa hampir semua kompiler untuk bahasa apa pun untuk platform apa pun dapat mengikat antarmuka C eksternal dan tahu persis apa yang diharapkan, tetapi untuk antarmuka C ++, itu pada dasarnya tidak mungkin karena peraturan berubah tergantung pada kompiler mana, versi mana, dan yang mana Platform kode C ++ dibuat.

Dalam C, tidak ada aturan implementasi bahasa biner standar, juga, tetapi urutan besarnya lebih sederhana dan dalam praktiknya kompiler menggunakan aturan yang sama. Alasan lain yang membuat kode C ++ sulit untuk di-debug adalah tata bahasa rumit yang disebutkan di atas, karena para debugger sering kali tidak dapat menangani banyak fitur bahasa (tempatkan breakpoints dalam templat, perintah parse pointer casting di jendela tampilan data, dll.).

Kurangnya ABI standar (antarmuka biner aplikasi) memiliki konsekuensi lain - itu membuat pengiriman antarmuka C ++ ke tim / pelanggan lain menjadi tidak praktis karena kode pengguna tidak akan berfungsi kecuali jika dikompilasi dengan alat yang sama dan membangun opsi. Kami telah melihat sumber lain dari masalah ini - ketidakstabilan antarmuka biner karena kurangnya waktu kompilasi enkapsulasi.

- C ++ Cacat

Mason Wheeler
sumber
4
Anda harus mencatat bahwa, walaupun dimungkinkan untuk mendefinisikan API mirip-C yang diimplementasikan dalam C ++ ( extern "C", masih banyak pekerjaan tambahan untuk melakukannya, yang harus diseimbangkan dengan fitur-fitur yang disediakan oleh C ++)
jhominal
5
C ++ ABI tidak relevan dalam konteks pertanyaan, di mana pustaka C ++ dapat dengan mudah diekspor extern "C".
DeadMG
12
@jhominal: Ini jauh lebih baik daripada menulisnya di C, di mana Anda harus mendefinisikan antarmuka C dan kemudian Anda juga harus mengimplementasikannya di C, sedangkan di C ++ Anda dapat mendefinisikan antarmuka C dan kemudian Anda tidak perlu mengimplementasikan di C. Tidak peduli bahasa apa yang Anda implementasikan, Anda masih harus mendefinisikan antarmuka C - ini tentu saja benar di C ++ seperti di C atau bahasa lain yang dapat mengekspos binding C.
DeadMG
9
Apakah mungkin untuk menambahkan disclaimer ke tautan ke FQA drivel itu?
Martin Ba
2
@DocBrown: Tentu bagi saya sepertinya pertanyaannya adalah tentang binding bahasa C vs. binding bahasa C ++.
Mason Wheeler
32

Jika Anda mencoba berkomunikasi dengan penutur bahasa lain, pidgin lebih mudah daripada bahasa Inggris Shakespeare.

Konsep C - panggilan fungsi, pointer, string yang diakhiri NULL - sangat mudah, sehingga bahasa lain dapat dengan mudah mengimplementasikannya dengan cukup baik untuk memanggil fungsi C. Karena alasan historis, banyak bahasa lain diimplementasikan dalam C, yang membuat pemanggilan fungsi C lebih mudah.

C ++ menambahkan sedikit hal - kelas, dengan warisan dan vtables dan pengubah akses; pengecualian, dengan tumpukan membuka dan mengubah aliran kontrol; template. Semua ini mempersulit bahasa lain untuk menggunakan binding C ++: paling-paling, ada lebih banyak "lem" atau kode interoperabilitas untuk diimplementasikan, dan paling buruk, konsep tidak diterjemahkan secara langsung (karena perbedaan dalam model kelas, penanganan pengecualian, dll.) Untuk template khususnya, cukup menggunakan (instantiating) mereka biasanya memerlukan langkah kompilasi dengan kompiler C ++, yang sangat menyulitkan menggunakannya dari lingkungan lain.

Dengan semua itu, mungkin untuk melebih-lebihkan kesulitan menyediakan binding dari pustaka C ++ ke bahasa lain:

  • Ikatan C ++ dapat sama kompatibel dengan C, jika Anda bersedia melakukannya. Seperti yang ditunjukkan oleh @DeadMG, dukungan C ++ extern "C", sehingga Anda dapat mengekspor binding bahasa gaya-C (dengan semua kesederhanaan dan kompatibilitas binding C) dari pustaka C ++ (dengan batasan bahwa Anda tidak dapat mengekspos C ++ - fungsionalitas khusus) .
  • Keberatan umum lainnya untuk binding bahasa C ++ adalah kurangnya stabilitas ABI untuk C ++, tetapi ini juga dilebih-lebihkan; C ++ ABI kurang standar dari C ABI, tetapi standar dan standar de facto memang ada (Itanium C ++ ABI, yang juga digunakan pada OS X ; standar de facto GCC untuk Linux). Windows lebih buruk, tetapi bahkan pada Windows, tetap dalam satu versi Visual C ++ harus bekerja dengan baik.
Josh Kelley
sumber
1
Masalah lain dengan menyediakan pengikatan dari pustaka C ++ ke bahasa lain adalah bahwa bahasa lain mungkin memerlukan binding untuk diimplementasikan dalam C. Atau, untuk bahasa yang memiliki sesuatu seperti (.NET) P / Invoke atau (python) ctypes, itu mungkin tidak menyediakan alat apa pun untuk menggunakan C ++ ABI.
Random832
6
@ Random832: Yang sama sekali tidak relevan ketika sisi C ++ dapat dengan mudah menawarkan antarmuka C. Anda tidak harus menerapkan pengikatan dalam C untuk menawarkan pengikatan C.
DeadMG
21

C adalah salah satu bahasa tertua yang masih ada. ABI-nya sederhana, dan hampir setiap sistem operasi yang masih digunakan saat ini telah ditulis di dalamnya . Sementara beberapa OS tersebut mungkin telah menambahkan hal-hal misalnya dalam C # /. NET atau apa pun di atas, di bawah mereka sangat mendalami C.

Itu berarti bahwa, untuk menggunakan fungsionalitas yang disediakan oleh OS, hampir setiap bahasa pemrograman di luar sana membutuhkan cara untuk berinteraksi dengan C perpustakaan pula . Perl, Java, C ++, mereka semua secara native menyediakan cara untuk "berbicara C", karena mereka harus jika mereka tidak ingin menemukan kembali setiap roda yang ada.

Ini menjadikan C bahasa Latin dari bahasa pemrograman. (Berapa tahun internet sebelum metafora itu harus menjadi "bahasa Inggris untuk bahasa pemrograman"?)


Saat Anda menulis pustaka di C, Anda mendapatkan antarmuka yang kompatibel dengan C secara gratis (jelas). Jika Anda menulis perpustakaan Anda di C ++, Anda bisa mendapatkan binding C, melalui extern "C"deklarasi seperti yang Anda sebutkan.

Namun , Anda bisa mendapatkan orang-binding hanya untuk fungsi yang dapat dinyatakan dalam C .

Jadi API perpustakaan Anda tidak dapat menggunakan ...

  • templat,
  • kelas,
  • pengecualian,
  • fungsi yang mengambil atau mengembalikan objek.

Salah satu contoh sederhana, Anda perlu membuat fungsi yang diekspor mengambil dan mengembalikan array ( []) alih-alih std::vector(atau std::stringdalam hal ini).

Jadi, tidak hanya Anda tidak dapat memberikan hal-hal baik yang ditawarkan C ++ kepada klien perpustakaan Anda, Anda juga harus melakukan upaya tambahan untuk "menerjemahkan" API perpustakaan Anda dari C ++ ke "C kompatibel" ( extern "C").

Itulah mengapa poin dapat dibuat bahwa C adalah pilihan yang lebih baik untuk mengimplementasikan perpustakaan. Secara pribadi, saya pikir manfaat C ++ masih lebih besar daripada upaya yang diperlukan untuk extern "C"API, tapi itu hanya saya.

DevSolar
sumber
Windows tampaknya akan mencoba mendasarkan dirinya pada. NET, Android berbasis di sekitar Java (juga C sebagai detail implementasi untuk beberapa API), dan iOS / OSX berbasis di sekitar Objective-C.
user253751
1
Bahasa Inggris sudah menjadi bahasa yang dominan di dunia pemrograman. Lebih dominan dari pada profesi lain.
Siyuan Ren
3
@immibis: Windows, Linux / Android, dan BSD / OSX semuanya kernel ditulis dalam C, dengan antarmuka ditulis dalam (dan untuk) C. Tidak peduli apa yang dibangun di atas itu, Java membutuhkan JNI, Perl perlu panggilan C,. NET membutuhkan panggilan C, Python membutuhkan panggilan C, Objective-C membutuhkan panggilan C. Tidak satu pun dari mereka yang membutuhkan panggilan C ++, yang merupakan titik yang saya coba buat.
DevSolar
@DevSolar Banyak hal Android ditulis secara asli di Java dan tidak menggunakan JNI (Anda dapat menggunakannya "mundur" untuk memanggil kode Java dari C, tetapi itu hanya lebih jauh menegaskan bahwa itu asli Java). Tidak ada pengalaman dengan iOS / OSX tapi saya dengar itu sama dengan Objective-C.
user253751
3
@immibis: Tapi Anda lakukan tahu perbedaan antara kernel OS dan userspace nya, bukan? Saya benar-benar meragukan sebagian besar ruang pengguna Java membuat Android lebih kurang sebagai kernel Linux dengan panggilan sistem C-style daripada kernel Linux yang berjalan di desktop saya. Saya juga ragu mereka menggunakan Java di kernel, atau di middleware. Sebenarnya, saya tahu mereka menggunakan C di sana. Ini masalah ayam dan telur, hanya sebaliknya. Ini telah dilakukan di C sebelumnya, dan dengan demikian jauh lebih mudah untuk tetap melakukannya di C.
DevSolar
6

Meninggalkan detail jawaban lain sudah memberikan:

Alasan mengapa begitu banyak bahasa menyediakan ikatan C adalah karena semua * nix dan sistem operasi Windows memaparkan sebagian besar API OS mereka melalui antarmuka C. Jadi implementasi bahasa sudah perlu antarmuka dengan C untuk dapat berjalan pada Oses utama. Oleh karena itu, sangat mudah untuk juga menawarkan komunikasi langsung dengan antarmuka C dari bahasa itu sendiri.

Martin Ba
sumber
5

Tidak ada alasan. Jika semantik yang ingin Anda ekspresikan pada dasarnya kompatibel dengan C dan bukan sesuatu seperti templat, tidak ada alasan Anda dapat mengikat lebih mudah jika implementasinya ditulis dalam C. Sebenarnya, cukup banyak definisi bahwa antarmuka C dapat diisi oleh implementasi apa pun yang dapat memenuhi kontrak biner - termasuk implementasi dalam bahasa lain. Ada bahasa selain C ++ yang dapat mengimplementasikan kontrak biner C yang dapat bekerja dengan cara ini.

Apa yang sebenarnya menjadi intinya adalah orang-orang yang tidak ingin belajar bahasa atau ide-ide baru yang sebenarnya memiliki semantik atau fitur yang mati-matian berusaha untuk mengambil alasan untuk tetap berada di era dinosaurus.

DeadMG
sumber
4
Saya pikir Anda benar dan downvoter salah memahami pertanyaan, tetapi sebenarnya jawaban Anda tidak ingin menyoroti potensi kesalahpahaman: pertanyaannya bukan tentang "perpustakaan dengan antarmuka C" vs. "perpustakaan dengan antarmuka C ++", ini tentang "perpustakaan yang seluruhnya ditulis dalam C" vs. "perpustakaan dengan antarmuka C yang ditulis dalam C ++".
Doc Brown
@Snowman: Memiliki binding C ++ yang bermasalah sama sekali tidak ada hubungannya dengan masalah dengan mengekspos binding C.
DeadMG
2
Jadi, Anda akan memilih bahasa yang memiliki semantik dan fitur yang berguna, dan kemudian memaksa diri Anda untuk menerjemahkannya menjadi antarmuka C? Sementara kelas dan templat mungkin dapat dihindari (tetapi ajukan pertanyaan mengapa Anda menggunakan C ++ di tempat pertama), setiap fungsi dengan penjilidan C harus menangkap pengecualian alih-alih membiarkan mereka melarikan diri ke dalam kode C. Belum lagi bahwa siapa pun yang menggunakan pustaka kompatibel C Anda sekarang harus berurusan dengan C ++ dan ketidakcocokan perpustakaan dan ketidakcocokan perpustakaannya dengan ABI, selain ketidakcocokan media dan ketidakcocokan perpustakaan C.
prosfilaes
2
@prosfilaes: Ini sepele untuk mengubah pengecualian menjadi kode kembali. Anda tidak perlu menghindari penggunaan kelas karena itu dapat dengan mudah diturunkan menjadi API C dan Anda tidak perlu menghindari menggunakan templat dalam implementasi Anda. Dan pengguna Anda tidak perlu peduli tentang bentrokan C ++ ABI kecuali mereka membangun dari sumber, dalam hal ini, Anda harus berurusan dengan bahasa sumber tidak peduli apa itu.
DeadMG
4
Saya downvoted bukan karena orang tidak harus menulis perpustakaan dengan C API di C ++, tetapi karena ada alasan bagus untuk menggunakan C selain menjadi dinosaurus. Jika Anda menulis untuk API dalam bahasa X, baik itu C, FORTRAN, COBOL, BLISS, atau Java selalu ada waktu di mana itu akan menjadi lebih sederhana, lebih mudah dan lebih benar untuk menulis dalam bahasa itu kemudian menulis di pelamun , lebih menyenangkan bahasa dan antarmuka keduanya.
prosfila
2

Ada dua sumbu utama saat berinteraksi dengan bahasa lain:

  • konsep yang dapat dibawa oleh antarmuka: hanya nilai? referensi? obat generik?
  • bagaimana antarmuka diimplementasikan dalam "binari" (disebut ABI)

C memiliki keunggulan dibandingkan C ++ di kedua bidang tersebut:

  • C hanya memiliki sebagian besar konsep sederhana, yang muncul di sebagian besar setiap bahasa lain 1
  • Binari ABI C ditentukan oleh OS 2

Sekarang, mengapa sebagian besar bahasa memiliki seperangkat konsep yang sama daripada C mungkin karena itu baik "sederhana" atau "sudah ada"; tidak masalah, intinya mereka melakukannya.

Sebaliknya, C ++ memiliki konsep yang kompleks, dan ABI ditentukan oleh masing-masing kompiler (meskipun banyak yang mematuhi ABI Itanimum, kecuali pada Windows ...). Sebenarnya ada proposal oleh Herb Sutter untuk meminta OS memperbaiki C ++ ABI (berdasarkan per OS) untuk mengatasi sebagian masalah ini. Juga, orang harus mencatat bahwa C ++ FFI adalah mungkin, D sedang mencobanya 3 .

1 Kecuali variadics ( ...), itu tidak sederhana

2 Apakah C memiliki ABI standar?

3 Menghubungkan kode D ke Legacy C ++

Matthieu M.
sumber
0

Pada dasarnya itu turun ke standardisasi ABI. Sementara C atau C ++ tidak memiliki ABI standar yang dapat digunakan bahasa lain untuk antarmuka antara biner yang ditulis, C telah menjadi standar de-facto, semua orang tahu dan semua orang dapat menggunakan aturan yang sama, sederhana, yang dimiliki bahasa sehubungan dengan jenis dan panggilan fungsi.

C ++ dapat memiliki ABI standar, tetapi Stroustrup mengatakan bahwa ia tidak melihat perlunya ABI. Dia juga mengatakan akan sulit untuk mendapatkan konsensus dari penulis kompiler (meskipun saya ragu bahwa - komite standar C ++ akan mengeluarkan ABI yang mirip dengan yang ada dan penulis kompiler hanya akan mengubah versi berikutnya dari kompiler mereka, yang kadang-kadang tidak kompatibel dengan biner. dibangun dengan versi lama kompiler mereka - saya ingat mengkompilasi ulang beberapa perpustakaan dengan kompiler Sun baru dan menemukan mereka gagal bekerja dengan yang lama)

Anda akan mencatat bahwa beberapa perusahaan telah pindah ke menggunakan ABI standar, Microsoft memulai proses ini dengan cara COM kembali di tahun 90-an, dan hari ini mereka telah menyempurnakan ini menjadi WinRT ABI (jangan bingung dengan WinRT lain yang merujuk ke jenis tabel OS) yang memungkinkan program yang ditulis dalam C # untuk berkomunikasi dengan perpustakaan yang ditulis dalam C atau C ++ (yaitu lapisan OS Microsoft sendiri ditulis dalam C ++, diekspos menggunakan WinRT dan dikonsumsi oleh aplikasi C # ketika mereka memanggil rutin runtime OS)

Tidak banyak yang bisa dilakukan orang kecuali badan standar meningkatkan dan memperbaiki situasi ini. Microsoft jelas melihat nilai di dalamnya dan telah mengambil langkah-langkah untuk menyelesaikannya untuk platform mereka.

Jadi jawabannya benar-benar C tidak memberikan ikatan bahasa. Itu terjadi bahwa tidak ada yang mendengarkan dan mengkonsumsinya terlepas.

gbjbaanb
sumber
-2

Semua jawaban gagal dari masalah sebenarnya: kompilasi C ++ memperkenalkan "name mangling", sehingga biner tidak kompatibel dengan pemanggilan fungsi "sederhana".

Semua hal ABI lebih dari sekadar upaya untuk membakukannya.

Secara umum itu tidak dijamin Anda dapat cross-link fungsi dikompilasi dengan kompiler yang berbeda, bahkan jika Anda tetap menggunakan C ++. Sebelumnya yakin mereka tidak kompatibel, tetapi saat ini standardisasi merayap masuk;)

OTOH C dirancang dengan tepat untuk menjadi "Majelis tingkat tinggi" dan memungkinkan semua jenis antarmuka yang mudah. Seharusnya tidak mengejutkan itu lebih cocok untuk menyukai lintas bahasa.

Catatan: kompiler C ++ asli (cfront) sebenarnya menghasilkan sumber C yang harus dikompilasi, persis seperti gcc yang menghasilkan Majelis "di bawah tenda".

ZioByte
sumber