Apakah file header sebenarnya bagus? [Tutup]

20

Saya menemukan file header berguna ketika menelusuri file sumber C ++, karena mereka memberikan "ringkasan" dari semua fungsi dan anggota data dalam suatu kelas. Mengapa banyak bahasa lain (seperti Ruby, Python, Java, dll.) Tidak memiliki fitur seperti ini? Apakah ini area di mana V ++ sangat berguna?

Matt Fichman
sumber
Saya tidak terbiasa dengan alat-alat dalam C dan C ++, tetapi kebanyakan IDE / editor kode tempat saya bekerja memiliki tampilan "struktur" atau "garis besar".
Michael K
1
File header tidak baik - mereka diperlukan! - Lihat juga jawaban ini di SO: stackoverflow.com/a/1319570/158483
Pete

Jawaban:

31

Tujuan asli dari file header adalah untuk memungkinkan kompilasi single-pass dan modularitas dalam C. Dengan mendeklarasikan metode sebelum digunakan, itu hanya diperbolehkan untuk satu kompilasi pass. Usia ini sudah lama berlalu berkat komputer kami yang kuat mampu melakukan kompilasi multi-pass tanpa masalah, dan kadang-kadang bahkan lebih cepat daripada kompiler C ++.

C ++ yang kompatibel dengan C diperlukan untuk menjaga file header, tetapi menambahkan banyak di atasnya, yang menghasilkan desain yang cukup bermasalah. Lebih banyak di FQA .

Untuk modularitas, file header diperlukan sebagai metadata tentang kode dalam modul. Misalnya. metode apa (dan di kelas C ++) tersedia di perpustakaan apa. Jelas ada pengembang yang menulis ini, karena waktu kompilasi mahal. Saat ini, tidak ada masalah untuk memiliki kompiler menghasilkan metadata ini dari kode itu sendiri. Bahasa Java dan .NET melakukan ini secara normal.

Jadi tidak. File header tidak bagus. Itu ketika kita masih harus memiliki kompiler dan linker pada disket terpisah dan kompilasi memakan waktu 30 menit. Saat ini, mereka hanya menghalangi dan merupakan tanda dari desain yang buruk.

Euforia
sumber
8
Saya setuju dengan sebagian besar dari apa yang Anda tulis, tetapi paragraf terakhir membuat semuanya menjadi sedikit sederhana. File header masih melayani tujuan yang berguna untuk mendefinisikan antarmuka publik.
Benjamin Bannier
3
@honk Itulah yang saya maksud dengan pertanyaan saya. Tapi saya pikir IDE modern (seperti yang disarankan oleh ElYusubov) agak meniadakan ini.
Matt Fichman
5
Anda dapat menambahkan bahwa komite C ++ sedang mengerjakan Modul yang akan membuat C dan C ++ dapat bekerja tanpa header ATAU dengan header yang digunakan dengan cara yang lebih efisien. Itu akan membuat jawaban ini lebih adil.
Klaim
2
@MattFichman: Menghasilkan beberapa file header adalah satu hal (yang sebagian besar editor / IDE programmer dapat lakukan secara otomatis dalam beberapa cara), tetapi intinya tentang API publik adalah bahwa hal itu secara efektif perlu didefinisikan dan dirancang oleh manusia yang sebenarnya.
Benjamin Bannier
2
@ Ya Ya. Tetapi tidak ada alasan untuk ini didefinisikan dalam file terpisah. Itu bisa dalam kode yang sama dengan implementasi. Sama seperti C # yang melakukannya.
Euforia
17

Meskipun mereka mungkin berguna bagi Anda sebagai bentuk dokumentasi, sistem yang mengelilingi file header sangat tidak efisien.

C dirancang sehingga setiap pass kompilasi membangun satu modul tunggal; setiap file sumber dikompilasi dalam menjalankan terpisah dari kompiler. File header, di sisi lain, disuntikkan ke langkah kompilasi untuk masing-masing file sumber yang mereferensikannya.

Ini berarti bahwa jika file header Anda termasuk dalam 300 file sumber, maka file tersebut akan diuraikan dan dikompilasi berulang-ulang, 300 kali terpisah saat program Anda dibuat. Hal yang persis sama dengan hasil yang sama persis, berulang-ulang.Ini sangat membuang waktu, dan merupakan salah satu alasan utama mengapa program C dan C ++ membutuhkan waktu lama untuk dibangun.

Semua bahasa modern sengaja menghindari inefisiensi kecil yang absurd ini. Alih-alih, biasanya dalam bahasa yang dikompilasi, metadata yang diperlukan disimpan dalam output build, memungkinkan file yang dikompilasi untuk bertindak sebagai semacam referensi pencarian cepat yang menjelaskan apa yang terkandung dalam file yang dikompilasi. Semua manfaat file header, secara otomatis dibuat tanpa ada pekerjaan tambahan di pihak Anda.

Bergantian dalam bahasa yang ditafsirkan, setiap modul yang dimuat akan tetap tersimpan dalam memori. Merujuk atau memasukkan atau membutuhkan pustaka akan membaca dan menyusun kode sumber terkait, yang tetap penduduk sampai program berakhir. Jika Anda juga memerlukannya di tempat lain, tidak ada pekerjaan tambahan karena sudah dimuat.

Dalam kedua kasus tersebut, Anda dapat "menelusuri" data yang dibuat oleh langkah ini menggunakan alat bahasa. Biasanya IDE akan memiliki semacam browser kelas. Dan jika bahasa tersebut memiliki REPL, itu juga dapat sering digunakan untuk menghasilkan ringkasan dokumentasi dari setiap objek yang dimuat.

tylerl
sumber
5
tidak sepenuhnya benar - sebagian besar, jika tidak semua, kompilator melakukan pra-kompilasi header seperti yang mereka lihat sehingga memasukkannya ke dalam unit kompilasi berikutnya tidak lebih buruk daripada menemukan blok kode pra-kompilasi. Tidak ada bedanya dengan, misalnya, kode .NET berulang kali 'membangun' system.data.types untuk setiap file C # yang Anda kompilasi. Alasan mengapa program C / C ++ memakan waktu begitu lama adalah karena mereka sebenarnya dikompilasi (dan dioptimalkan). Semua program .NET perlu diurai menjadi IL, runtime melakukan kompilasi aktual melalui JIT. Yang mengatakan, 300 file sumber dalam kode C # membutuhkan beberapa waktu untuk mengkompilasi juga.
gbjbaanb
7

Tidak jelas, apa yang Anda maksud dengan menelusuri file untuk fungsi dan anggota data. Namun, sebagian besar IDE menyediakan Alat untuk menjelajah kelas dan melihat anggota data kelas.

Misalnya: Visual Studio telah Class Viewdan Object browserdengan baik menyediakan fungsionalitas yang Anda minta. Seperti di cuplikan layar berikut.

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

EL Yusubov
sumber
4

Kerugian tambahan dari file header adalah bahwa program tergantung pada urutan penyertaannya, dan programmer harus mengambil langkah-langkah tambahan untuk memastikan kebenaran.

Itu, ditambah dengan sistem makro C (diwarisi oleh C ++), menyebabkan banyak jebakan dan situasi membingungkan.

Sebagai ilustrasi, jika satu tajuk mendefinisikan beberapa simbol menggunakan makro untuk penggunaannya, dan tajuk lainnya menggunakan simbol dengan cara lain seperti nama untuk suatu fungsi, maka urutan inklusi akan sangat mempengaruhi hasil akhir. Ada banyak contoh seperti itu.

jcora
sumber
2

Saya selalu menyukai file header karena mereka menyediakan bentuk antarmuka untuk implementasi, bersama dengan beberapa informasi tambahan seperti variabel kelas, semua dalam satu file yang mudah dilihat.

Saya melihat banyak kode C # (yang tidak perlu 2 file per kelas) ditulis menggunakan 2 file per kelas - satu implementasi kelas aktual, dan satu lagi dengan antarmuka di dalamnya. Desain ini baik untuk mengejek (penting dalam beberapa sistem) dan membantu untuk mendefinisikan dokumentasi kelas tanpa harus menggunakan IDE untuk melihat metadata yang dikompilasi. Sejauh ini saya akan mengatakan praktik yang baik.

Jadi C / C ++ mandat setara (dari macam) antarmuka dalam file header adalah hal yang baik.

Saya tahu ada pendukung sistem lain yang tidak menyukai mereka karena alasan termasuk 'lebih sulit untuk hanya meretas kode jika Anda harus meletakkan sesuatu dalam 2 file', tetapi sikap saya adalah bahwa hanya meretas kode bukan praktik yang baik pula , dan begitu Anda mulai menulis / mendesain kode dengan sedikit lebih banyak pemikiran, maka Anda akan mendefinisikan header / antarmuka sebagai hal yang biasa.

gbjbaanb
sumber
Antarmuka dan Implementasi dalam file yang berbeda? Jika Anda memerlukan ini dengan desain, ini masih sangat umum untuk mendefinisikan antarmuka (atau kelas abstrak) dalam bahasa seperti Java / C # dalam satu file dan menyembunyikan implementasinya pada file lain. Ini tidak memerlukan file header yang lama dan rumit.
Petter Nordlander
eh? bukankah itu yang saya katakan - Anda mendefinisikan antarmuka dan implementasi kelas dalam 2 file.
gbjbaanb
2
baik, itu tidak memerlukan file header dan itu tidak membuat file header lebih baik. Ya, mereka diperlukan dalam bahasa dengan warisan, tetapi sebagai konsep mereka tidak diperlukan untuk membagi antarmuka / implementasi dalam file yang berbeda (sebenarnya, mereka membuatnya lebih buruk).
Petter Nordlander
@Petter Saya pikir Anda salah paham, secara konseptual mereka tidak berbeda - ada header untuk menyediakan antarmuka dalam bahasa C, dan meskipun Anda benar - Anda dapat menggabungkan 2 (seperti banyak dilakukan dengan kode C hanya header) yang bukan praktik terbaik yang pernah saya lihat diikuti di banyak tempat. Semua C # devs yang kulihat memisahkan antarmuka dari kelas, misalnya. Ini praktik yang baik untuk melakukan ini karena Anda dapat memasukkan file antarmuka ke beberapa file lain tanpa polusi. Sekarang, jika Anda berpikir bahwa split ini adalah praktik terbaik (itu) maka cara untuk mencapainya di C adalah dengan menggunakan file header.
gbjbaanb
Jika header benar-benar berguna untuk memisahkan antarmuka dan implementasi, hal-hal seperti PImpl tidak diperlukan untuk menyembunyikan komponen pribadi dan memisahkan pengguna akhir dari keharusan mengkompilasi ulang terhadap mereka. Sebaliknya, kita mendapatkan yang terburuk dari kedua dunia. Header berpura-pura fasad pemisahan yang cepat diberhentikan, sambil membuka segudang perangkap, yang memerlukan kode verplose boilerplate jika Anda perlu mengatasinya.
underscore_d
1

Saya benar-benar akan mengatakan bahwa file header tidak bagus karena mereka memperkeruh antarmuka dan implementasi. Maksud dengan pemrograman pada umumnya, dan terutama OOP adalah untuk memiliki antarmuka yang ditentukan dan menyembunyikan detail implementasi, tetapi file header C ++ menunjukkan kepada Anda metode, warisan, dan anggota publik (antarmuka) serta metode pribadi dan anggota pribadi (beberapa bagian dari implementasi). Belum lagi dalam beberapa kasus Anda pada akhirnya memasukkan kode atau konstruktor dalam file header, dan beberapa perpustakaan menyertakan kode template dalam header, yang benar-benar memadukan implementasi dengan antarmuka.

Maksud asli, saya percaya, adalah untuk memungkinkan kode menggunakan perpustakaan lain, objek, dll tanpa harus mengimpor seluruh isi skrip. Yang Anda butuhkan adalah tajuk untuk dikompilasi dan ditautkan. Menghemat waktu dan siklus dengan cara itu. Dalam hal itu, itu ide yang baik, tetapi itu hanya satu cara untuk menyelesaikan masalah ini.

Adapun untuk menelusuri struktur program, sebagian besar IDE menyediakan kemampuan itu, dan ada banyak alat yang akan menendang keluar antarmuka, melakukan analisis kode, dekompilasi, dll sehingga Anda dapat melihat apa yang terjadi di bawah selimut.

Adapun mengapa bahasa lain tidak menerapkan fitur yang sama? Ya, karena bahasa lain berasal dari orang lain, dan para desainer / pencipta tersebut memiliki visi yang berbeda tentang bagaimana segala sesuatu harus bekerja.

Jawaban terbaik adalah tetap dengan apa pekerjaan yang perlu Anda lakukan, dan membuat Anda bahagia.

Maurice Reeves
sumber
0

Dalam banyak bahasa pemrograman, ketika suatu program dibagi lagi menjadi beberapa unit kompilasi, kode dalam satu unit hanya akan dapat menggunakan hal-hal yang didefinisikan dalam unit lain jika kompiler memiliki beberapa cara untuk mengetahui apa saja itu. Daripada mengharuskan kompilator memproses satu unit kompilasi memeriksa seluruh teks dari setiap unit kompilasi yang mendefinisikan apa pun yang digunakan dalam unit ini, yang terbaik adalah menerima kompiler, sambil memproses setiap unit, teks lengkap dari unit yang akan dikompilasi bersama dengan sedikit informasi dari yang lain.

Di C, programmer bertanggung jawab untuk membuat dua file untuk setiap unit - satu berisi informasi yang hanya akan diperlukan ketika mengkompilasi unit itu, dan satu berisi informasi yang juga akan diperlukan ketika menyusun unit lainnya. Ini adalah desain yang agak jahat, hacky, tapi itu menghindari kebutuhan untuk memiliki standar bahasa menentukan apa pun tentang bagaimana kompiler harus menghasilkan dan memproses file perantara. Banyak bahasa lain menggunakan pendekatan yang berbeda, di mana kompiler akan menghasilkan dari masing-masing file sumber file perantara yang menggambarkan segala sesuatu dalam file sumber yang seharusnya dapat diakses oleh kode luar. Pendekatan ini menghindari perlunya memiliki informasi duplikat dalam dua file sumber, tetapi mengharuskan platform kompilasi telah mendefinisikan semantik file dengan cara yang tidak diperlukan untuk C.

supercat
sumber