İfadeleri, başlığı veya kaynağı nereye koymalı?


107

İçerenleri başlık dosyasına mı yoksa kaynak dosyaya mı koymalıyım? Başlık dosyası include ifadelerini içeriyorsa, bu başlık dosyasını kaynağıma eklersem, kaynak dosyamda başlığımda bulunan tüm dahil edilen dosyalar olur mu? Yoksa bunları yalnızca kaynak dosyama mı eklemeliyim?


2
SO'da önceki birçok kopya, örneğin C ++ 'da nereye "dahil edilmelidir"
Paul R

Yanıtlar:


141

Yalnızca başlığın kendisi bunlara ihtiyaç duyuyorsa bir başlığa ekleyin.

Örnekler:

  • İşleviniz türü döndürür size_t. Sonra #include <stddef.h>içinde başlık dosyasında.
  • İşleviniz kullanır strlen. Sonra #include <string.h>içinde kaynak dosyası.

2
Ya işlevim bir tür bağımsız değişken alırsa size_t?
andrybak

Aynı soru c ++ 'ya genişliyor: ya benim yapı / sınıfımın bir türü / üyesi varsa size_tveya std::string?
andrybak

10
Gerekçe nedir?
Patrizio Bertoni

Kablolu bir durumum var, C ++ sınıf A'nın başka bir B sınıfından bir nesnesi var ve B'nin ileri bildirimini ve A başlığının içindeki B başlığı dahil olmak üzere sonlandırmayı kullanamıyorum. (işaretçi kullanmanın bu sorunu yok)
shuva

@andrybak Kaynak dosyalarınız Başlık dosyanızı içermelidir, böylece başlığınız dahil herhangi biri kaynağınızı alır.
Jeremy Trifilo

27

Yıllar geçtikçe bu konuda epey anlaşmazlık oldu. Bir zamanlar, bir başlığın yalnızca ilişkili olduğu modülde ne olduğunu bildirmesi gelenekseldi , pek çok başlığın, belirli #includebir başlık setine (belirli bir sırayla) sahip olmanız için belirli gereksinimleri vardı . Bazı aşırı geleneksel C programcıları hala bu modeli takip ediyor (en azından bazı durumlarda dini olarak).

Daha yakın zamanlarda, çoğu başlığı bağımsız hale getirme yönünde bir hareket var. Bu başlık başka bir şey gerektiriyorsa, başlığın kendisi bunu halleder ve ihtiyaç duyduğu her şeyin dahil edilmesini sağlar (sipariş sorunları varsa doğru sırada). Şahsen ben bunu tercih ederim - özellikle başlıkların sıralaması önemli olduğunda, onu kullanan herkesten sorunu tekrar çözmesini istemek yerine sorunu bir kez çözer.

Çoğu üstbilginin yalnızca bildirimler içermesi gerektiğini unutmayın. Bu, gereksiz bir üstbilgi eklemenin (normalde) son çalıştırılabilir dosyanıza herhangi bir etkisi olmaması gerektiği anlamına gelir. En kötüsü, derlemeyi biraz yavaşlatmasıdır.


2
Tüm başlıklar ikinci tarzda yazılırsa, hiçbir sıralama sorunu olmamalıdır. Başlıklarda sipariş sorunları olması genellikle ihtiyacınız olan her şeyi başlığa eklemediğiniz anlamına gelir.
Hoşçakal SE

12

URL'leriniz #includebaşlık dosyalarından olmalı ve her dosya (kaynak veya başlık) #includeihtiyaç duyduğu başlık dosyalarında olmalıdır . Başlık dosyaları, #includegerekli minimum başlık dosyalarına sahip olmalıdır ve kaynak dosyaları da olmalıdır, ancak kaynak dosyalar için o kadar önemli değildir.

Kaynak dosya, başlıklarına #includeve bunların başlıklarına sahip olacaktır #includeve bu, maksimum yuvalama derinliğine kadar devam eder. Bu yüzden #includebaşlık dosyalarında gereksiz dosyalar istemezsiniz : bunlar, bir kaynak dosyanın ihtiyaç duymayabileceği çok sayıda başlık dosyası içermesine ve derlemeyi yavaşlatmasına neden olabilir.

Bu, başlık dosyalarının iki kez dahil edilebilmesinin tamamen mümkün olduğu ve bu bir sorun olabileceği anlamına gelir. Geleneksel yöntem başlık dosyalarına "include guards" koymaktır, örneğin foo.h dosyası için:

#ifndef INCLUDE_FOO_H
#define INCLUDE_FOO_H
/* everything in header goes here */
#endif

Bu cevabın çok eski olduğunu biliyorum, ancak o zamandan beri #pragma'yı bir kez eklediler, bu yüzden #includes'ı ilan ederken #ifndef'i eklemek istemezsiniz çünkü bu daha eski ama daha popüler / yukarı oy verilen konular Google aramalarının en üstünde olma eğilimindedir
Dogunbound tazıları

6

Yirmi yılı aşkın bir süredir geliştirdiğim yaklaşım şudur;

Bir kitaplık düşünün.

Birden çok C dosyası, bir dahili H dosyası ve bir harici H dosyası vardır. C dosyaları, dahili H dosyasını içerir. Dahili H dosyası, harici H dosyasını içerir.

Derleyiciler POV'dan bir C dosyası derlediği için bir hiyerarşi olduğunu görüyorsunuz;

harici -> dahili -> C kodu

Bu, doğru sıralamadır, çünkü harici olan, üçüncü bir şahsın kütüphaneyi kullanmak için ihtiyaç duyduğu her şeydir. Dahili olan, C kodunu derlemek için gereklidir.


4

Başlık dosyası A #includesbaşlık dosyası B ve C ise, #includesA'nın her kaynak dosyası da B ve C'yi alır #included. Ön işlemci, kelimenin tam anlamıyla sadece metin değiştirme işlemini gerçekleştirir: her yerde, onu dosya #include <foo.h>metniyle değiştirdiğini söyleyen metni bulur foo.h.

#includesBaşlıklar mı yoksa kaynak dosyalar mı koymanız gerektiği konusunda farklı görüşler vardır . Kişisel olarak, #includesvarsayılan olarak tümünü kaynak dosyaya koymayı tercih ederim , ancak diğer ön koşul başlıkları olmadan derlenemeyen üstbilgi dosyaları, #includebu başlıkların kendileri olabilir.

Ve her başlık dosyası, birden çok kez eklenmesini önlemek için bir kapsama koruması içermelidir.


4

Bazı ortamlarda, biri yalnızca ihtiyaç duyulan başlık dosyalarını içeriyorsa, derleme en hızlı olacaktır. Diğer ortamlarda, tüm kaynak dosyalar aynı birincil başlık koleksiyonunu kullanabiliyorsa, derleme optimize edilecektir (bazı dosyalar ortak alt kümenin dışında ek başlıklara sahip olabilir). İdeal olarak, birden çok #include işleminin hiçbir etkisi olmayacak şekilde üstbilgiler oluşturulmalıdır. #İnclude deyimlerini, dahil edilecek dosyanın include korumasına yönelik denetimlerle çevrelemek iyi olabilir, ancak bu, söz konusu korumanın biçimine bir bağımlılık yaratır. Ayrıca, bir sistemin dosya önbelleğe alma davranışına bağlı olarak, hedefi tamamen # ifdef'le sonuçlanan gereksiz bir #include uzun sürmeyebilir.

Dikkate alınması gereken başka bir şey de, eğer bir işlev bir yapıya işaretçi götürürse, prototipi şu şekilde yazabilir:

void foo (struct BAR_s * bar);

Kapsam içinde olması gereken BAR_s için bir tanım olmadan. Gereksiz içeriklerden kaçınmak için çok kullanışlı bir yaklaşım.

Not - Projelerimin çoğunda, her modülün #inclu olmasının beklendiği, tamsayı boyutları için typedef'ler ve birkaç ortak yapı ve birleşim gibi şeyler içeren bir dosya olacak [örn.

typedef union {
  imzasız uzun l;
  işaretsiz kısa lw [2];
  işaretsiz karakter lb [4];
} U_QUAD;

(Evet, bir big-endian mimarisine geçersem başımın belaya gireceğini biliyorum, ancak derleyicim sendikalarda anonim yapılara izin vermediğinden, birlik içindeki baytlar için adlandırılmış tanımlayıcılar kullanmak, bunlara şu şekilde erişilmesini gerektirecektir. theUnion.b.b1 vb. oldukça sinir bozucu görünüyor.


3

Tüm dosyalarınızı yalnızca içerdiklerini kullanarak oluşturulabilecek şekilde yapın. Başlığınıza eklemeye ihtiyacınız yoksa kaldırın. Büyük bir projede, bu disiplini sürdürmezseniz, birisi başlık dosyasından ve hatta bu dosyanın tüketicisi tarafından kullanılan bir başlık dosyasından bir eklemeyi kaldırdığında, tüm yapıyı bozmaya açık kalırsınız.


1

Başlığa koyarsanız, kaynak dosyanız include ifadelerine sahip olacaktır. Ancak, bazı durumlarda bunları kaynak dosyaya koymak daha iyi olabilir.

Bu başlığı başka bir kaynağa eklerseniz, başlıktan da dahil edileceklerini ve bunun her zaman arzu edilmediğini unutmayın. Yalnızca kullanıldığı yerlere eklemelisiniz.


1

Başlığınıza yalnızca sabitleri ve işlev bildirimlerini bildirmeniz gereken dosyaları eklemelisiniz. Teknik olarak, bu içerikler de kaynak dosyanıza eklenecektir, ancak netlik açısından, her dosyaya yalnızca gerçekten kullanmanız gereken dosyaları eklemelisiniz. Bunları başlığınızda birden fazla eklenmekten de korumalısınız, böylece:

#ifndef NAME_OF_HEADER_H
#define NAME_OF_HEADER_H

...definition of header file...

#endif

Bu, başlığın birden çok kez dahil edilmesini engeller ve bir derleyici hatasıyla sonuçlanır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.