#include in .h or .c / .cpp?

118

Saat membuat kode dalam C atau C ++, di mana saya harus memilikinya #include?

callback.h:

#ifndef _CALLBACK_H_
#define _CALLBACK_H_

#include <sndfile.h>
#include "main.h"

void on_button_apply_clicked(GtkButton* button, struct user_data_s* data);
void on_button_cancel_clicked(GtkButton* button, struct user_data_s* data);

#endif

callback.c:

#include <stdlib.h>
#include <math.h>

#include "config.h"

#include "callback.h"
#include "play.h"

void on_button_apply_clicked(GtkButton* button, struct user_data_s* data) {
  gint page;
  page = gtk_notebook_get_current_page(GTK_NOTEBOOK(data->notebook));

  ...

Haruskah semua menyertakan baik dalam .h atau .c / .cpp, atau keduanya seperti yang telah saya lakukan di sini?

Louise
sumber
2
Izinkan saya membalikkan keadaan ini dan bertanya: apa kriteria Anda untuk memutuskan meletakkan sndfile.h dan main.h di callback.h?
Owen S.

Jawaban:

161

Masukkan sebanyak yang Anda bisa .cdan sesedikit mungkin ke dalam .h. Termasuk dalam .chanya disertakan ketika satu file itu dikompilasi, tetapi termasuk untuk .hharus disertakan oleh setiap file yang menggunakannya.

Brendan Long
sumber
6
Benar, tetapi bukankah #ifndef _CALLBACK_H_, di atasnya, mencegah compiler untuk memprosesnya lebih dari sekali?
hytromo
11
@ user9379 Hal itu akan mencegahnya disertakan lebih dari sekali per file .c atau .cpp. Setiap file .c atau .cpp umumnya dibangun secara individual, yang berarti .h akan diurai ulang untuk setiap file .c atau .cpp yang Anda kompilasi.
Brendan Long
2
Saya pikir alasan utama untuk memasukkan sesedikit mungkin .hadalah untuk menghindari kesalahan dalam beberapa kasus karena lingkaran inklusi. Contoh: dua kelas membutuhkan satu sama lain untuk implementasinya, tetapi tidak untuk deklarasinya. Menempatkan keduanya termasuk dalam .cpps akan menghindari kesalahan.
Codoscope
1
@ Qu'est-cet'yont Itulah alasan mengapa Anda tidak dapat memasukkan hal-hal tertentu ke dalam file .h. Jawaban ini adalah tentang mengapa Anda harus memberikan lebih sedikit dari itu.
Brendan Long
@BrendanLong Begitu, meskipun dalam pengertian saya memasukkan beberapa kali tajuk yang sama tidak masalah jika Anda meletakkan makro yang benar di dalam untuk memasukkan konten hanya sekali. Oleh karena itu, menurut saya menempatkan lebih sedikit adalah untuk mengurangi kemungkinan mendapatkan kesalahan di masa depan dengan modifikasi kode.
Codoscope
55

Satu-satunya saat Anda harus menyertakan header di dalam file .h lainnya adalah jika Anda perlu mengakses definisi tipe di header itu; sebagai contoh:

#ifndef MY_HEADER_H
#define MY_HEADER_H

#include <stdio.h>

void doStuffWith(FILE *f); // need the definition of FILE from stdio.h

#endif

Jika header A bergantung pada header B seperti contoh di atas, maka header A harus menyertakan header B secara langsung. Apakah TIDAK mencoba untuk memesan Anda termasuk dalam file c untuk memenuhi dependensi (yaitu, termasuk sundulan B sebelum sundulan A); itu adalah tumpukan besar mulas yang menunggu untuk terjadi. Saya sungguh-sungguh. Saya telah berada di film itu beberapa kali, dan itu selalu berakhir dengan Tokyo terbakar.

Ya, hal ini dapat mengakibatkan file disertakan beberapa kali, tetapi jika file tersebut memiliki pelindung include yang tepat yang disiapkan untuk melindungi dari beberapa kesalahan deklarasi / definisi, beberapa detik tambahan waktu pembuatan tidak perlu dikhawatirkan. Mencoba mengelola dependensi secara manual sangat merepotkan.

Tentu saja, Anda tidak boleh memasukkan file yang tidak Anda perlukan .

John Bode
sumber
10

Masukkan sebanyak mungkin include di cpp Anda dan hanya yang dibutuhkan oleh file hpp di hpp tersebut. Saya yakin ini akan membantu mempercepat kompilasi, karena file hpp akan lebih sedikit referensi silang.

Pertimbangkan juga untuk menggunakan deklarasi penerusan dalam file hpp Anda untuk lebih mengurangi rantai ketergantungan include.

Parappa
sumber
1
Oo. Hal deklarasi maju itu menarik.
Brendan Long
Parappa, deklarasi maju sangat berguna dalam skenario referensi melingkar. Tapi apakah mereka akan menjadi praktik yang baik dalam skenario lain? (Saya baru dalam C ++, jadi saya benar-benar bertanya)
Dzyann
5

Jika saya #include <callback.h>, saya tidak ingin memiliki #includebanyak file header lain untuk mendapatkan kode saya untuk dikompilasi. Dalam callback.hAnda harus menyertakan semua yang diperlukan untuk mengkompilasi terhadapnya. Tapi tidak lebih.

Pertimbangkan apakah menggunakan deklarasi maju di file header Anda (seperti class GtkButton;) sudah cukup, memungkinkan Anda mengurangi jumlah #includearahan di header (dan, pada gilirannya, waktu kompilasi dan kerumitan saya).

Johnsyweb
sumber
Saya tidak setuju. Memasukkan seluruh dunia dalam file H meningkatkan rantai ketergantungan dan karenanya waktu kompilasi.
John Dibling
Jawaban saya tidak merekomendasikan termasuk seluruh dunia dalam file header, saya menyarankan termasuk hanya cukup sehingga pengguna API tidak harus menghabiskan waktu untuk mencari dependensi.
Johnsyweb