Alasan sebenarnya datang ke perbedaan mendasar dalam niat antara C dan C ++ di satu sisi, dan Java dan C # (hanya untuk beberapa contoh) di sisi lain. Untuk alasan historis, banyak diskusi di sini berbicara tentang C daripada C ++, tetapi (karena Anda mungkin sudah tahu) C ++ adalah keturunan C yang cukup langsung, jadi apa yang dikatakan tentang C berlaku sama untuk C ++.
Meskipun mereka sebagian besar dilupakan (dan keberadaan mereka kadang-kadang bahkan ditolak), versi pertama UNIX ditulis dalam bahasa assembly. Sebagian besar (jika tidak semata-mata) tujuan asli C adalah port UNIX dari bahasa assembly ke bahasa level yang lebih tinggi. Bagian dari tujuannya adalah untuk menulis sebanyak mungkin sistem operasi dalam bahasa tingkat yang lebih tinggi - atau melihatnya dari arah lain, untuk meminimalkan jumlah yang harus ditulis dalam bahasa assembly.
Untuk mencapai itu, C perlu menyediakan tingkat akses yang hampir sama ke perangkat keras seperti bahasa assembly. PDP-11 (misalnya) memetakan register I / O ke alamat tertentu. Misalnya, Anda akan membaca satu lokasi memori untuk memeriksa apakah suatu tombol telah ditekan pada konsol sistem. Satu bit diatur di lokasi itu ketika ada data yang menunggu untuk dibaca. Anda kemudian akan membaca byte dari lokasi lain yang ditentukan untuk mengambil kode ASCII dari tombol yang telah ditekan.
Demikian juga, jika Anda ingin mencetak beberapa data, Anda akan memeriksa lokasi lain yang ditentukan, dan ketika perangkat output siap, Anda akan menulis data Anda lagi lokasi lain yang ditentukan.
Untuk mendukung driver penulisan untuk perangkat tersebut, C memungkinkan Anda untuk menentukan lokasi sewenang-wenang menggunakan beberapa jenis integer, mengubahnya menjadi sebuah pointer, dan membaca atau menulis lokasi itu dalam memori.
Tentu saja, ini memiliki masalah yang cukup serius: tidak semua mesin di bumi memiliki ingatannya yang identik dengan PDP-11 dari awal 1970-an. Jadi, ketika Anda mengambil bilangan bulat itu, mengonversinya menjadi sebuah pointer, dan kemudian membaca atau menulis melalui pointer itu, tidak ada yang bisa memberikan jaminan yang masuk akal tentang apa yang akan Anda dapatkan. Hanya untuk contoh yang jelas, membaca dan menulis dapat dipetakan ke register terpisah di perangkat keras, sehingga Anda (bertentangan dengan memori normal) jika Anda menulis sesuatu, kemudian mencoba membacanya kembali, apa yang Anda baca mungkin tidak cocok dengan apa yang Anda tulis.
Saya dapat melihat beberapa kemungkinan yang tersisa:
- Tentukan antarmuka untuk semua perangkat keras yang mungkin - tentukan alamat absolut dari semua lokasi yang Anda ingin baca atau tulis untuk berinteraksi dengan perangkat keras dengan cara apa pun.
- Larang tingkat akses itu, dan putuskan bahwa siapa pun yang ingin melakukan hal-hal seperti itu perlu menggunakan bahasa majelis.
- Izinkan orang melakukan itu, tetapi serahkan pada mereka untuk membaca (misalnya) manual untuk perangkat keras yang mereka targetkan, dan menulis kode agar sesuai dengan perangkat keras yang mereka gunakan.
Dari jumlah tersebut, 1 tampaknya tidak masuk akal sehingga sulit untuk didiskusikan lebih lanjut. 2 pada dasarnya membuang niat dasar bahasa tersebut. Itu meninggalkan opsi ketiga sebagai satu-satunya yang mereka anggap masuk akal.
Poin lain yang cukup sering muncul adalah ukuran tipe integer. C mengambil "posisi" yang int
seharusnya merupakan ukuran alami yang disarankan oleh arsitektur. Jadi, jika saya memprogram VAX 32-bit, int
mungkin seharusnya 32 bit, tetapi jika saya memprogram 36-bit Univac, int
mungkin harus 36 bit (dan seterusnya). Mungkin tidak masuk akal (dan bahkan mungkin tidak mungkin) untuk menulis sistem operasi untuk komputer 36-bit hanya menggunakan tipe yang dijamin kelipatan 8 bit. Mungkin saya hanya menjadi dangkal, tetapi bagi saya sepertinya jika saya menulis OS untuk mesin 36-bit, saya mungkin ingin menggunakan bahasa yang mendukung tipe 36-bit.
Dari sudut pandang bahasa, ini mengarah pada perilaku yang lebih tidak terdefinisi. Jika saya mengambil nilai terbesar yang akan masuk ke dalam 32 bit, apa yang akan terjadi ketika saya menambahkan 1? Pada perangkat keras 32-bit yang khas, itu akan berguling (atau mungkin melemparkan semacam kesalahan perangkat keras). Di sisi lain, jika itu berjalan pada perangkat keras 36-bit, itu hanya akan ... menambahkan satu. Jika bahasa tersebut akan mendukung sistem operasi penulisan, Anda tidak dapat menjamin perilaku mana pun - Anda harus membiarkan ukuran jenis dan perilaku overflow bervariasi dari satu ke yang lain.
Java dan C # dapat mengabaikan semua itu. Mereka tidak dimaksudkan untuk mendukung sistem operasi penulisan. Dengan mereka, Anda memiliki beberapa pilihan. Salah satunya adalah membuat perangkat keras mendukung apa yang mereka inginkan - karena mereka menuntut jenis yang 8, 16, 32 dan 64 bit, buat saja perangkat keras yang mendukung ukuran tersebut. Kemungkinan lain yang jelas adalah agar bahasa hanya berjalan di atas perangkat lunak lain yang menyediakan lingkungan yang mereka inginkan, terlepas dari apa yang mungkin diinginkan perangkat keras yang mendasarinya.
Dalam kebanyakan kasus, ini sebenarnya bukan pilihan baik / atau. Sebaliknya, banyak implementasi melakukan sedikit dari keduanya. Anda biasanya menjalankan Java pada JVM yang berjalan pada sistem operasi. Lebih sering daripada tidak, OS ditulis dalam C, dan JVM dalam C ++. Jika JVM berjalan pada CPU ARM, kemungkinan cukup bagus bahwa CPU menyertakan ekstensi Jazelle ARM, untuk menyesuaikan perangkat keras lebih dekat dengan kebutuhan Java, jadi lebih sedikit yang perlu dilakukan dalam perangkat lunak, dan kode Java berjalan lebih cepat (atau kurang lambat, pokoknya).
Ringkasan
C dan C ++ memiliki perilaku yang tidak jelas, karena tidak ada yang mendefinisikan alternatif yang dapat diterima yang memungkinkan mereka untuk melakukan apa yang seharusnya mereka lakukan. C # dan Java mengambil pendekatan yang berbeda, tetapi pendekatan itu kurang cocok (jika sama sekali) dengan tujuan C dan C ++. Secara khusus, tampaknya tidak ada cara yang masuk akal untuk menulis perangkat lunak sistem (seperti sistem operasi) pada sebagian besar perangkat keras yang dipilih secara sewenang-wenang. Keduanya biasanya tergantung pada fasilitas yang disediakan oleh perangkat lunak sistem yang ada (biasanya ditulis dalam C atau C ++) untuk melakukan pekerjaan mereka.