Mengapa ada begitu sedikit kompiler C?

72

C adalah salah satu bahasa yang paling banyak digunakan di dunia. Ini menyumbang sebagian besar kode yang ada dan terus digunakan untuk sejumlah besar kode baru. Ini disukai oleh para penggunanya, itu sangat banyak porting sehingga mampu menjalankan C adalah untuk banyak definisi informal dari platform , dan dipuji oleh para penggemarnya karena bahasa "kecil" dengan serangkaian fitur yang relatif bersih.

Jadi di mana semua kompiler?

Di desktop, ada (secara realistis) dua : GCC dan Dentang. Memikirkannya selama beberapa detik, Anda mungkin akan ingat Intel juga ada. Ada beberapa yang lain, terlalu tidak jelas untuk orang rata-rata untuk disebutkan dan hampir secara universal tidak peduli untuk mendukung versi bahasa baru-baru ini (atau seringkali bahkan bagian bahasa yang terdefinisi dengan baik, hanya "bagian"). Setengah dari anggota daftar ini adalah catatan kaki sejarah; sebagian besar sisanya sangat terspesialisasi dan masih belum benar-benar menerapkan bahasa lengkap. Sangat sedikit yang tampaknya merupakan open-source.

Skema dan Keempat - bahasa kecil lainnya yang disukai oleh penggemar mereka untuk itu - mungkin memiliki lebih banyak kompiler daripada pengguna sebenarnya. Bahkan sesuatu seperti SML memiliki implementasi yang lebih "serius" untuk dipilih daripada C. Sedangkan pengumuman kompiler C yang baru (belum selesai) yang bertujuan untuk verifikasi sebenarnya melihat beberapa tanggapan yang cukup negatif, dan implementasi veteran berjuang untuk mendapatkan cukup kontributor untuk mengejar ketinggalan. C99.

Mengapa? Apakah menerapkan C sangat sulit? Itu bukan C ++. Apakah pengguna hanya memiliki gagasan yang sangat miring tentang kelompok kerumitan apa itu (yaitu bahwa sebenarnya lebih dekat ke C ++ daripada Skema)?


sumber
61
MSVC masih dianggap, sebagai kompiler C89 setidaknya. Mungkin bahkan lebih populer daripada Intel.
Rufflewind
22
Wikipedia mencantumkan beberapa kompiler C. Mereka menjadi sangat umum ketika Anda menemukan diri Anda di dunia tertanam.
113
berapa banyak kompiler yang Anda perlukan untuk mengkompilasi kode C Anda?
Bryan Chen
76
Pertanyaannya didasarkan pada premis yang salah. Perangkat Analog, armcc, Bruce's C Compiler, Bare-C Cross Compiler, compiler Borland, compiler dentang, kompiler Cosmic C, kompiler CodeWarrior, kompiler dokto, kompiler dokto, kompiler Ericsson, dan saya bahkan tidak keluar dari lima huruf pertama dari alfabet. Ada sejumlah besar kompiler C. Pertanyaannya adalah "mengapa ada begitu sedikit kompiler C, jika kita tidak menghitung beberapa lusin ini sebagai kompiler C nyata?" Anda telah mendefinisikan sebagian besar kompiler C sebagai tidak menarik, itulah sebabnya tidak banyak.
Eric Lippert
19
Pertanyaan "Mengapa" adalah pertanyaan buruk untuk situs ini pada saat terbaik, dan "mengapa tidak?" pertanyaan lebih buruk. Jika saya bertemu dengan Anda di sebuah pesta dan bertanya "jadi, mengapa Anda tidak berlomba perahu layar?" Saya pikir Anda akan menganggapnya sebagai pertanyaan aneh. Anda tidak perlu memberikan pembenaran untuk TIDAK terlibat dalam hobi yang secara teknis sulit, berisiko secara fisik, dan sangat mahal. Menulis perangkat lunak yang tidak sepele adalah mahal, sulit dan berisiko dan karenanya membutuhkan motivator yang sangat besar . Pertanyaan yang lebih baik adalah "mengapa ada begitu banyak kompiler C?" Sangat mengejutkan bahwa ada lebih dari satu.
Eric Lippert

Jawaban:

153

Hari ini, Anda memerlukan C compiler nyata untuk menjadi compiler mengoptimalkan , terutama karena C tidak lagi menjadi bahasa dekat dengan hardware, karena saat ini prosesor yang sangat kompleks ( out-of-order , pipelined , superscalar , dengan kompleks cache & TLB , karenanya perlu penjadwalan instruksi , dll ...). Prosesor x86 saat ini tidak seperti prosesor i386 abad sebelumnya, meskipun keduanya mampu menjalankan kode mesin yang sama. Lihat C bukan bahasa tingkat rendah (Komputer Anda bukan PDP-11 cepat) karya David Chisnall.

Hanya sedikit orang yang menggunakan kompiler C non-optimisif yang naif seperti tinycc atau nwcc , karena mereka menghasilkan kode yang beberapa kali lebih lambat daripada yang diberikan oleh kompiler optimisasi.

Pengkodean kompiler pengoptimalisasi sulit. Perhatikan bahwa baik GCC dan Dentang mengoptimalkan beberapa representasi kode "sumber bahasa-netral" (Gimple untuk GCC, LLVM untuk Dentang). Kompleksitas kompiler C yang baik tidak dalam fase parsing!

Secara khusus, membuat kompiler C ++ tidak jauh lebih sulit daripada membuat kompiler C: parsing C ++ dan mengubahnya menjadi beberapa representasi kode internal yang kompleks (karena spesifikasi C ++ kompleks), tetapi dipahami dengan baik, tetapi bagian optimasinya bahkan lebih kompleks (di dalam GCC: optimisasi ujung-tengah, bahasa sumber dan prosesor target netral, membentuk mayoritas dari kompiler, dengan sisanya diseimbangkan antara ujung depan untuk beberapa bahasa dan ujung belakang untuk beberapa prosesor). Karenanya sebagian besar kompiler C yang mengoptimalkan juga dapat mengkompilasi beberapa bahasa lain, seperti C ++, Fortran, D, ... Bagian spesifik C ++ dari GCC adalah sekitar 20% dari kompiler ...

Juga, C (atau C ++) sangat banyak digunakan sehingga orang berharap kode mereka dapat dikompilasi bahkan ketika itu tidak benar-benar mengikuti standar resmi, yang tidak mendefinisikan secara tepat semantik bahasa (sehingga setiap kompiler dapat memiliki interpretasinya sendiri. itu). Lihatlah juga ke CompCert terbukti C compiler, dan Frama-C analyzer statis, yang peduli lebih formal semantik dari C.

Dan optimisasi adalah fenomena panjang : menerapkan beberapa optimasi sederhana itu mudah, tetapi mereka tidak akan membuat kompiler kompetitif! Anda perlu menerapkan banyak optimasi berbeda, dan untuk mengatur dan menggabungkannya dengan cerdas, untuk mendapatkan kompiler dunia nyata yang kompetitif. Dengan kata lain, kompiler yang mengoptimalkan dunia nyata harus menjadi perangkat lunak yang kompleks. BTW, baik GCC dan Dentang / LLVM memiliki beberapa generator kode khusus C / C ++ internal. Dan keduanya adalah binatang buas besar (beberapa juta baris kode sumber, dengan tingkat pertumbuhan beberapa persen setiap tahun) dengan komunitas pengembang besar (beberapa ratus orang, sebagian besar bekerja penuh waktu, atau setidaknya setengah waktu).

Perhatikan bahwa tidak ada (setahu saya) compiler C multi-threaded, bahkan jika beberapa bagian dari kompiler dapat dijalankan secara paralel (misalnya optimasi intra-prosedural, alokasi register, penjadwalan instruksi ...). Dan build paralel dengan make -jtidak selalu cukup (terutama dengan KPP ).

Juga, sulit untuk mendapatkan dana pada pengkodean kompiler C dari awal, dan upaya seperti itu perlu berlangsung beberapa tahun. Akhirnya, sebagian besar kompiler C atau C ++ adalah perangkat lunak gratis saat ini (tidak ada lagi pasar untuk kompiler eksklusif yang dijual oleh startup) atau setidaknya adalah komoditas monopolistik (seperti Microsoft Visual C ++ ), dan menjadi perangkat lunak bebas hampir diperlukan untuk kompiler ( karena mereka memerlukan kontribusi dari berbagai organisasi).

Saya akan senang mendapatkan dana untuk bekerja pada kompiler C dari awal sebagai perangkat lunak bebas, tetapi saya tidak cukup naif untuk percaya bahwa itu mungkin hari ini!

Basile Starynkevitch
sumber
14
(there is no more a market for proprietary compilersKatakan itu kepada tim Visual Studio ...
Mason Wheeler
18
Microsoft memiliki monopoli. Maksud saya, perusahaan kecil yang mengembangkan kompiler C baru tidak akan menjual banyak dari mereka. Bisakah Anda menyebutkan pesaing eksklusif untuk MSVC?
Basile Starynkevitch
12
Ada banyak kompiler eksklusif di dunia HPC. PGCC, NAG, dan ICC adalah yang paling banyak digunakan.
Davidmh
37
@MasonWheeler: VS diberikan gratis saat ini (seperti dalam bir). Versi yang tidak bebas menambahkan tooling, tetapi kompiler C di VS2013 adalah sama di semua versi. Tidak ada pasar, bahkan untuk mereka.
MSalters
3
Tetapi kedua GCC & LLVM beroperasi pada representasi yang jauh lebih rendah, dan mereka juga mengoptimalkan kode C ++ & C (& Ada & Fortran, untuk GCC). Sebaliknya saya akan mengatakan bahwa C ++ memerlukan lebih banyak optimasi (terutama ketika mengkompilasi kode menggunakan STL) daripada C!
Basile Starynkevitch
70

Saya ingin menentang asumsi mendasar Anda bahwa hanya ada sejumlah kecil implementasi C.

Saya bahkan tidak tahu C, saya tidak menggunakan C, saya bukan anggota komunitas C, namun, bahkan saya tahu jauh lebih banyak daripada beberapa kompiler yang Anda sebutkan.

Pertama dan terpenting, ada kompiler yang mungkin benar-benar jauh lebih kecil baik GCC maupun Dentang pada desktop: Microsoft Visual C. Meskipun ada terobosan yang dibuat baik oleh OSX dan Linux di desktop, dan pangsa pasar yang dicuri oleh iOS dan Android "dicuri" jauh dari mantan pengguna desktop tradisional, Windows masih dalam OS desktop yang dominan, dan sebagian besar program desktop Windows C mungkin disusun menggunakan alat Microsoft.

Secara tradisional, setiap vendor OS dan setiap vendor chip memiliki kompiler mereka sendiri. Microsoft, sebagai vendor OS, memiliki Microsoft Visual C. IBM, sebagai vendor OS dan vendor chip, memiliki XLC (yang merupakan kompiler sistem default untuk AIX, dan kompiler yang dikompilasi dengan AIX dan i / OS) . Intel memiliki kompiler sendiri. Sun / Oracle memiliki kompiler sendiri di Sun Studio.

Lalu, ada vendor kompiler berkinerja tinggi seperti PathScale dan The Portland Group, yang kompilernya (dan pustaka OpenMP) digunakan untuk angka-angka.

Digital Mars juga masih dalam bisnis. Saya percaya Walter Bright memiliki perbedaan unik menjadi satu-satunya orang di planet ini yang berhasil membuat kompiler C ++ berkualitas-produksi (kebanyakan) sendiri.

Terakhir, kami memiliki semua kompiler berpemilik untuk mikrokontroler tertanam. IIRC, ada lebih banyak mikrokontroler yang dijual setiap tahun daripada desktop, mobile, server, workstation, dan mainframe CPU yang telah terjual dalam seluruh sejarah komputasi yang digabungkan. Jadi, itu jelas bukan produk niche.

Penghargaan kehormatan diberikan kepada TruffleC , juru bahasa C (!) Yang menjalankan JVM (!) Yang ditulis menggunakan kerangka kerja juru bahasa Truffle AST yang hanya 7% lebih lambat daripada GCC dan Dentang (mana yang paling cepat pada tolok ukur tertentu yang diberikan) di seluruh Komputer Bahasa Game Benchmark, dan lebih cepat dari keduanya di microbenchmark. Dengan menggunakan TruffleC, tim Truffle dapat memperoleh versi JRuby + Truffle untuk mengeksekusi ekstensi Ruby C lebih cepat daripada implementasi C Ruby yang sebenarnya!

Jadi, ini adalah 6 implementasi selain dari yang Anda sebutkan yang dapat saya sebutkan di atas kepala saya, tanpa tahu apa-apa tentang C.

Jörg W Mittag
sumber
1
Di luar Microsoft Visual C, sebagian besar kompiler C yang Anda sebutkan jarang digunakan.
Basile Starynkevitch
6
MSVC adalah kompiler C ++ besar, tetapi untuk C sulit digunakan dan terjebak secara permanen di C89; kompiler mikrokontroler biasanya target-spesifik, terjebak dalam C89, dan unik; TruffleC tampaknya belum tersedia (tetapi menarik, terima kasih). Pathscale dan Digital Mars sepertinya lebih mirip contoh tandingan yang saya cari.
Leushenko
8
@ Mario maksud saya bukan bahwa C89 rusak, tetapi C89 bukan bentuk bahasa terkini; dan itu berarti lebih sedikit kompiler yang up-to-date ada.
Leushenko
6
@Leushenko MSVC tidak terjebak secara permanen di C89. Ada beberapa diskusi dan lebih banyak fitur C99 yang harus ditambahkan. Sebagai permulaan, sebagian besar perpustakaan C99 didukung pada MSVC 2015 dan beberapa fitur bahasa juga (terutama hal-hal yang diperlukan untuk C ++ 11).
Morwenn
5
@Morwenn: Kebijakan Microsoft tampaknya adalah bahwa C99 tidak menyelesaikan masalah yang belum diselesaikan oleh C ++, dan bahwa jika Anda melakukan pemrograman sistem, Anda harus menggunakan subset seperti-C dari C ++ (segala sesuatu yang tidak memerlukan runtime atau di mana Anda tidak dapat mengontrol di mana kompiler akan meletakkan sesuatu - penting jika Anda perlu memastikan bahwa kode atau data tidak keluar dari status di mana paging dinonaktifkan). Satu-satunya fitur dari C99 adalah hal-hal yang diperlukan dalam spesifikasi C ++ kemudian, dan yang tidak perlu diimplementasikan.
Mike Dimmick
8

Berapa banyak kompiler yang Anda butuhkan?

Jika mereka memiliki set fitur yang berbeda, Anda membuat masalah portabilitas. Jika mereka komoditi Anda memilih "default" (GCC, Dentang atau VS). Jika Anda peduli dengan kinerja 5% terakhir, Anda memiliki tolok ukur.

Jika Anda melakukan pekerjaan bahasa pemrograman secara rekreasional atau untuk tujuan penelitian, kemungkinan bahasa tersebut lebih modern. Oleh karena itu proliferasi kompiler mainan untuk Skema dan ML. Meskipun OCaml tampaknya mendapatkan daya tarik untuk penggunaan non-akademik non-mainan.

Perhatikan ini sangat bervariasi berdasarkan bahasa. Java pada dasarnya memiliki Sun / Oracle toolchain dan GNU. Python memiliki berbagai kompiler yang tidak ada yang benar-benar dihormati dibandingkan dengan penerjemah standar. Rust dan Go memiliki persis satu implementasi masing-masing. C # memiliki Microsoft dan Mono.

pjc50
sumber
1
Sudah jelas bahwa ada alasan yang lebih menarik untuk mengembangkan kompiler ML ... Saya hanya berpikir bahwa komunitas C yang mungkin tiga urutan lebih besar akan menyeimbangkan efek yang keluar. Tapi Anda mungkin benar, 1000 * 0masih 0.
Leushenko
Membuat kompiler baru sering dikaitkan dengan fragmentasi komunitas (baik disebabkan oleh atau menyebabkan). Misalnya, split egcs vs gcc maintainer. Juga, kompatibilitas sumber C cenderung di bawah 100%.
pjc50
@ pjc50: Cara standar ditulis secara efektif membagi C menjadi beberapa dialek terpisah berdasarkan hal-hal seperti tipe dasar int, dan akan membutuhkan kompiler yang berbeda untuk menafsirkan kode sumber yang sama dengan cara yang sangat berbeda.
supercat
5
Saya percaya, Go memiliki dua implementasi ( 6g/ 8g/ ... toolchain dan gccgo). Dulu juga ada implementasi komersial berpemilik yang sangat menarik yang disebut erGo, yang merupakan a) implementasi Windows asli Go pada saat tidak ada gccgo maupun kompiler Go asli yang bekerja dengan sangat baik pada Windows, b) perusahaan bertaruh pada Go, lama bahkan sebelum menjadi 1.0, dan c) implementasi Go yang pertama ditulis dalam Go (gccgo dan 6g / 8g keduanya ditulis dalam C). Namun baik proyek dan perusahaan menghilang, bahkan sebelum mereka keluar dari versi beta tertutup.
Jörg W Mittag
6

C / C ++ adalah unik di antara bahasa yang dikompilasi karena memiliki 3 implementasi utama dari spesifikasi umum.

Mengikuti aturan menolak apa pun yang tidak banyak digunakan, setiap bahasa yang dikompilasi lainnya memiliki 0 hingga 1.

Dan saya pikir javascript adalah satu-satunya alasan Anda perlu menentukan 'dikompilasi'.

soru
sumber
2
Label "C" diterapkan untuk sejumlah bahasa yang berbeda; beberapa mendefinisikan kode uint16_t a=48000u; unsigned uint32_t b=(a*a)/2;sebagai penetapan bnilai 8192. Beberapa mendefinisikannya sebagai penetapan 1152000000. Sebagian besar saat ini menganggapnya sebagai Perilaku Tidak Terdefinisi, dan kemungkinan untuk menyimpan 3299483648 tetapi tidak membuat janji dalam hal itu.
supercat
1
@supercat: Ah, aneh yang bagus dengan luapan dan aturan promosi integer. Itu bergantung pada penggunaan 2atau 2utampaknya.
Zan Lynx
1
@ ZanLynx: Saya tidak berpikir ada kasus di mana 2 versus 2u sah ; satu-satunya kasus yang saya tahu di mana masalahnya mungkin melibatkan Perilaku Tidak Terdefinisi dengan 2u dan 2u.
supercat
3
@supercat: bagaimana Anda mendapatkan perilaku yang tidak terdefinisi /2u? Overflow yang tidak ditandai didefinisikan (sebagai modulo 2 ^ N untuk implementasi yang ditentukan N) tetapi pembagian bahkan tidak dapat meluap.
MSalters
2
Perilaku Tidak Terdefinisi akan datang dari penggandaan nilai-nilai yang akan dipromosikan menjadi ditandatangani int, tetapi produk siapa yang tidak cocok dengan tipe itu. Memaksa hasil itu ke unsigned int kemungkinan akan mengubah interpretasi nilai yang dihasilkan, tetapi tidak akan meniadakan Perilaku Tidak Terdefinisi dari perhitungan sebelumnya.
supercat
5

Jadi apa bahasa target Anda?

Kompiler SML sering menargetkan C atau sesuatu seperti LLVM (atau seperti yang terlihat di tautan Anda, JVM atau JavaScript).

Jika Anda mengkompilasi C, itu bukan karena Anda akan pergi ke JVM. Anda akan mengalami sesuatu yang lebih buruk daripada C. Jauh lebih buruk. Dan kemudian Anda bisa menduplikasi neraka kecil itu beberapa kali untuk semua platform target Anda.

Dan tentu saja, C bukan C ++, tapi saya akan mengatakan bahwa lebih dekat ke C ++ daripada Skema. Itu memang memiliki subset sendiri dari kejahatan perilaku yang tidak terdefinisi (saya melihat Anda ukuran tipe built in). Dan jika Anda mengacaukan hal-hal kecil itu (atau melakukannya dengan "benar" tetapi tidak terduga) maka Anda memiliki dekade kode yang ada pada sistem vital yang akan memberi tahu Anda betapa buruknya Anda. Jika Anda mengacaukan kompiler SML, itu tidak akan berfungsi - dan seseorang mungkin memperhatikan. Suatu hari nanti.

Telastyn
sumber
SML / NJ dan PolyML sama-sama mengkompilasi ke kode mesin ...
Basile Starynkevitch
2
Bagaimana ukuran int "Perilaku Tidak Terdefinisi"? Dan mengapa UB menjadi beban bagi vendor kompiler? Satu-satunya beban nyata bagi penulis kompiler adalah lebar int adalah implementasi yang ditentukan, bukan tidak ditentukan, sehingga Anda harus mendokumentasikan apa yang Anda lakukan.
MSalters
@MSalters Pada kenyataannya, penulis kompiler untuk platform yang mapan memiliki beban untuk mencocokkan apa yang dilakukan orang lain sebelum mereka. Terkadang hal ini didokumentasikan dan distandarisasi, terkadang tidak. Sangat mudah untuk menemukan ukuran int, tetapi lebih sulit untuk menemukan apa yang dilakukan dengan nilai register dan di mana argumen disimpan ketika memanggil suatu fungsi (yang dapat berubah tergantung pada jenis argumen dan jenis kembali fungsi), aturan tata letak struct, dll
Random832
@MSalters Kebanyakan orang berharap intuntuk menjadi 32 atau 64 bit tetapi bisa sekecil 16 bit. Tidak sulit sama sekali untuk menghasilkan angka di luar jangkauan [−32767, +32767]dan intmelimpah adalah UB. Ada juga char/ shortdipromosikan ke int atau unsigned int tergantung pada apakah intdapat mewakili setiap nilai dari jenis asli, yang selanjutnya dapat memicu konversi dari intke unsigned intjika operan memiliki jenis yang berbeda dan dikonversi secara berbeda, ditambah kemungkinan konversi lain ketika Anda menetapkan hasilnya ke variabel .
Doval
@MSalters Ada cukup kelonggaran dalam ukuran tipe standar dan cukup konversi implisit yang saya bertaruh bahwa untuk hampir semua program C non-sepele ada pilihan ukuran integer hukum yang akan menyebabkannya melakukan hal yang salah atau menyebabkan undefined tingkah laku.
Doval