Di mana harus meletakkan pernyataan include, tajuk atau sumber?

107

Apakah saya harus memasukkan include di file header atau file sumber? Jika file header berisi pernyataan include, maka jika saya menyertakan file header itu di sumber saya, apakah file sumber saya akan memiliki semua file yang disertakan yang ada di header saya? Atau haruskah saya memasukkannya hanya dalam file sumber saya?

Mohit Deshpande
sumber
2
Banyak duplikat sebelumnya di SO, misalnya di mana harus "menyertakan" diletakkan di C ++
Paul R
1
kemungkinan duplikat dari Haruskah saya menggunakan #include in headers?
schot

Jawaban:

141

Hanya letakkan include di header jika header itu sendiri membutuhkannya.

Contoh:

  • Fungsi Anda mengembalikan tipe size_t. Kemudian #include <stddef.h>di file header .
  • Fungsi Anda menggunakan strlen. Kemudian #include <string.h>di file sumber .
schot
sumber
2
Bagaimana jika fungsi saya mengambil argumen tipe size_t?
andrybak
Pertanyaan yang sama berkembang ke c ++: bagaimana jika struct / class saya memiliki field / member bertipe size_tatau std::string?
andrybak
10
Apa alasannya?
Patrizio Bertoni
Saya memiliki situasi berkabel, C ++ kelas A memiliki objek kelas B lain, dan saya tidak dapat menggunakan deklarasi maju B dan berakhir termasuk header B di dalam header A. (menggunakan pointer tidak memiliki masalah ini)
shuva
@andrybak File Sumber Anda harus menyertakan file Header Anda sehingga semua yang menyertakan header Anda akan mendapatkan sumber Anda juga.
Jeremy Trifilo
27

Ada sedikit ketidaksepakatan tentang ini selama bertahun-tahun. Pada suatu waktu, sudah menjadi tradisi bahwa header hanya mendeklarasikan apa yang ada di modul apa pun yang terkait dengannya, begitu banyak header memiliki persyaratan khusus sehingga Anda #includememiliki sekumpulan header tertentu (dalam urutan tertentu). Beberapa programmer C yang sangat tradisional masih mengikuti model ini (secara religius, setidaknya dalam beberapa kasus).

Baru-baru ini, ada pergerakan untuk membuat sebagian besar tajuk berdiri sendiri. Jika tajuk itu membutuhkan sesuatu yang lain, tajuk itu sendiri yang menanganinya, memastikan bahwa apa pun yang dibutuhkannya disertakan (dalam urutan yang benar, jika ada masalah pengurutan). Secara pribadi, saya lebih suka ini - terutama ketika urutan tajuk bisa menjadi penting, ini memecahkan masalah sekali, daripada meminta semua orang yang menggunakannya untuk memecahkan masalah lagi.

Perhatikan bahwa kebanyakan header hanya berisi deklarasi. Ini berarti menambahkan tajuk yang tidak perlu seharusnya (biasanya) berdampak pada eksekusi akhir Anda. Hal terburuk yang terjadi adalah sedikit memperlambat kompilasi.

Jerry Coffin
sumber
2
Jika semua tajuk ditulis dalam gaya kedua, seharusnya tidak ada masalah urutan sama sekali. Memiliki masalah pengurutan di tajuk biasanya berarti Anda tidak menyertakan semua yang Anda butuhkan di tajuk.
Selamat tinggal SE
12

#includeS Anda harus berupa file header, dan setiap file (sumber atau header) harus #includeberupa file header yang dibutuhkannya. File header harus file #includeheader minimum yang diperlukan, dan file sumber juga harus, meskipun tidak sepenting file sumber.

File sumber akan memiliki header itu #include, dan headernya #include, dan seterusnya hingga kedalaman bersarang maksimum. Inilah sebabnya mengapa Anda tidak ingin kelebihan #includedalam file header: mereka dapat menyebabkan file sumber menyertakan banyak file header yang mungkin tidak diperlukan, memperlambat kompilasi.

Ini berarti sangat mungkin file header disertakan dua kali, dan itu bisa menjadi masalah. Metode tradisionalnya adalah dengan meletakkan "include guards" di file header, seperti ini untuk file foo.h:

#ifndef INCLUDE_FOO_H
#define INCLUDE_FOO_H
/* everything in header goes here */
#endif
David Thornley
sumber
Saya tahu jawaban ini sangat tua, tetapi sejak itu mereka menambahkan #pragma sekali jadi Anda tidak perlu menyertakan #ifndef saat mendeklarasikan #includes Saya memposting ini karena utas yang lebih lama tetapi lebih populer / disukai cenderung berada di bagian atas pencarian google
Anjing dogunbound
6

Pendekatan yang telah saya kembangkan selama lebih dari dua puluh tahun adalah ini;

Pertimbangkan perpustakaan.

Ada beberapa file C, satu file H internal dan satu file H eksternal. File C menyertakan file H. internal. File H internal menyertakan file H eksternal.

Anda melihat bahwa dari POV kompiler, saat ia mengkompilasi file C, ada hierarki;

eksternal -> internal -> kode C.

Ini adalah urutan yang benar, karena yang eksternal adalah semua yang dibutuhkan pihak ketiga untuk menggunakan perpustakaan. Yang internal diperlukan untuk mengkompilasi kode C.


sumber
4

Jika file header A #includessundulan file B dan C, maka setiap file sumber yang #includesA akan juga mendapatkan B dan C #included. Pra-prosesor secara harfiah hanya melakukan substitusi teks: di mana pun ia menemukan teks yang mengatakan #include <foo.h>ia menggantikannya dengan teks foo.hfile.

Ada beberapa pendapat berbeda tentang apakah Anda harus memasukkan #includesheader atau file sumber. Secara pribadi, saya lebih suka meletakkan semua #includesdalam file sumber secara default, tetapi file header apa pun yang tidak dapat dikompilasi tanpa header prasyarat lainnya harus #includeheader itu sendiri.

Dan setiap file header harus berisi penjaga penyertaan untuk mencegahnya disertakan beberapa kali.

Vicky
sumber
4

Di beberapa lingkungan, kompilasi akan menjadi tercepat jika seseorang hanya menyertakan file header yang dibutuhkan. Di lingkungan lain, kompilasi akan dioptimalkan jika semua file sumber dapat menggunakan kumpulan header utama yang sama (beberapa file mungkin memiliki header tambahan di luar subset umum). Idealnya, tajuk harus dibuat sehingga beberapa operasi #include tidak akan berpengaruh. Mungkin bagus untuk mengapit pernyataan #include dengan pemeriksaan file-to-be-Included's include-guard, meskipun hal itu menciptakan ketergantungan pada format penjaga itu. Lebih lanjut, bergantung pada perilaku cache file sistem, #include yang tidak perlu yang targetnya # ifdef'ed seluruhnya mungkin tidak butuh waktu lama.

Hal lain yang perlu dipertimbangkan adalah jika suatu fungsi membawa pointer ke struct, seseorang dapat menulis prototipe sebagai

void foo (struct BAR_s * bar);

tanpa definisi untuk BAR_s harus berada dalam cakupan. Pendekatan yang sangat berguna untuk menghindari penyertaan yang tidak perlu.

PS - di banyak proyek saya, akan ada file yang diharapkan setiap modul akan #include, berisi hal-hal seperti typedefs untuk ukuran integer dan beberapa struktur dan kesatuan umum [mis.

serikat typedef {
  l panjang tak bertanda tangan;
  unsigned short lw [2];
  unsigned char lb [4];
} U_QUAD;

(Ya, saya tahu saya akan mendapat masalah jika saya pindah ke arsitektur big-endian, tetapi karena kompiler saya tidak mengizinkan struct anonim dalam serikat, menggunakan pengidentifikasi bernama untuk byte dalam serikat akan mengharuskan mereka diakses sebagai theUnion.b.b1 dll. yang tampaknya agak mengganggu.

supercat
sumber
3

Buat semua file Anda agar dapat dibuat hanya menggunakan apa yang disertakan. Jika Anda tidak perlu menyertakan di header Anda, hapuslah. Dalam proyek besar jika Anda tidak mempertahankan disiplin ini, Anda membiarkan diri Anda terbuka untuk merusak seluruh build ketika seseorang menghapus penyertaan dari file header yang digunakan oleh konsumen file itu dan bahkan tidak oleh header.

memutarkan lagi
sumber
1

File sumber Anda akan memiliki pernyataan include jika Anda meletakkannya di header. Namun, dalam beberapa kasus, akan lebih baik untuk meletakkannya di file sumber.

Ingat bahwa jika Anda menyertakan tajuk itu di sumber lain, mereka juga akan mendapatkan penyertaan dari tajuk, dan itu tidak selalu diinginkan. Anda hanya boleh memasukkan barang di tempat yang digunakan.

Debu percikan
sumber
1

Anda hanya boleh menyertakan file di header yang Anda perlukan untuk mendeklarasikan konstanta dan deklarasi fungsi. Secara teknis, penyertaan ini juga akan disertakan dalam file sumber Anda, tetapi demi kejelasan, Anda hanya perlu menyertakan file yang benar-benar perlu Anda gunakan di setiap file. Anda juga harus melindunginya di header Anda dari beberapa penyertaan sebagai berikut:

#ifndef NAME_OF_HEADER_H
#define NAME_OF_HEADER_H

...definition of header file...

#endif

Ini mencegah header dimasukkan beberapa kali, mengakibatkan kesalahan compiler.

JRam930
sumber