Başlıkların CPP dosyasına açıkça eklenmesini sağlamak


10

#includeHPP dosyasıyla ne içerilmiş olduğuna bakılmaksızın, CPP dosyasında kullanılan herhangi bir tür için başlık için genellikle iyi bir uygulama olduğunu düşünüyorum . #include <string>Örneğin, hem HPP'mde hem de CPP'mde olabilir , yine de CPP'de atlasam derleyebilirim. Bu şekilde HPP'm ileri bir bildirim kullanıp kullanmadığından endişe duymam gerekmiyor.

Bu #includekodlama stilini uygulayabilecek araçlar var mı? Bu kodlama stilini zorlamalı mıyım ?

Önişlemci / derleyici #includeHPP veya CPP'den gelip gelmediğini umursamadığı için , bu stili izlemeyi unutursam geri bildirim almam.

Yanıtlar:


7

Bu tür kodlama standartlarının yerine "gerekir" den biridir. Bunun nedeni, hemen hemen bir C ++ ayrıştırıcısı uygulamak zorunda kalmanızdır.

Başlık dosyaları için çok yaygın bir kural, kendi başlarına durmaları gerektiğidir. Üstbilgi dosyası, söz konusu üstbilgiyi eklemeden önce başka bazı üstbilgi dosyalarının #include olmasını gerektirmemelidir. Bu test edilebilir bir gerekliliktir. Bazı rastgele üstbilgiler verildiğinde foo.hh, aşağıdakiler derlenmeli ve çalıştırılmalıdır:

#include "foo.hh"
int main () {
   return 0;
}

Bu kuralın, bazı üstbilgilerde diğer sınıfların kullanımı ile ilgili sonuçları vardır. Bazen bu sonuçlardan, diğer sınıfların ileriye doğru bildirilmesiyle önlenebilir. Standart kütüphane sınıflarının çoğunda bu mümkün değildir. std::stringVeya gibi bir şablon örneğini iletmenin bir yolu yoktur std::vector<SomeType>. Sen zorunda #includetip tek kullanım bir işleve argüman olarak olsa bile başlığında bu STL başlıklarını.

Başka bir sorun, tesadüfen sürüklediğiniz şeylerle ilgilidir. Örnek: aşağıdakileri göz önünde bulundurun:

dosya foo.cc:

#include "foo.hh"
#include "bar.hh"

void Foo::Foo () : bar() { /* body elided */ }

void Foo::do_something (int item) {
   ...
   bar.add_item (item);
   ...
}

İşte türünde barbir sınıf Fooveri üyesi Bar. Burada doğru olanı yaptınız ve sınıfı tanımlayan başlığa dahil edilmiş olsa bile #inc bar.hh eklediniz Foo. Ancak, Bar::Bar()ve tarafından kullanılan öğeleri eklemediniz Bar::add_item(int). Bu çağrıların ek harici referanslarla sonuçlanabileceği birçok durum vardır.

foo.oGibi bir araçla analiz ederseniz nm, içindeki fonksiyonlar foo.ccuygun olmayan her türlü şeyi çağırıyor gibi görünecektir #include. Peki, #includebu arızi harici referanslar için direktifler eklemeniz gerekir mi foo.cc? Cevap kesinlikle değil. Sorun, tesadüfen çağrılan işlevleri doğrudan çağrılan işlevlerden ayırmanın çok zor olmasıdır.


2

Bu kodlama stilini zorlamalı mıyım?

Muhtemelen değil. Kuralım şudur: üstbilgi dosyası eklenmesi siparişe bağlı olamaz.

Bunu xc'nin içerdiği ilk dosyanın xh olduğu basit kuralı ile kolayca doğrulayabilirsiniz.


1
Bu konuyu biraz açıklayabilir misiniz? Bunun sipariş bağımsızlığını gerçekten nasıl doğrulayacağını göremiyorum.
13'te

1
sipariş bağımsızlığını gerçekten garanti etmez - sadece bir öncekine #include "x.h"gerek kalmadan çalışmasını sağlar #include. İstismar etmiyorsan yeterince iyi #define.
kevin cline

1
Ah anlıyorum. Yine de iyi bir fikir.
13'te

2

Belirli başlık dosyalarının kendi başlarına durması gerektiğine dair bir kural uygulamanız gerekiyorsa, sahip olduğunuz araçları kullanabilirsiniz. Her başlık dosyasını ayrı ayrı derleyen ancak bir nesne dosyası oluşturmayan temel bir makefile oluşturun. Üstbilgi dosyasını (C veya C ++ modunda) derleyecek modu belirleyebilir ve kendi başına durabildiğini doğrulayabilirsiniz. Çıktının yanlış pozitif içermediği, gerekli tüm bağımlılıkların bildirildiği ve çıktının doğru olduğu konusunda makul bir varsayım yapabilirsiniz.

Bir IDE kullanıyorsanız, bunu bir makefile olmadan da yapabilirsiniz (IDE'nize bağlı olarak). Yalnızca ek bir proje oluşturun, doğrulamak istediğiniz başlık dosyalarını ekleyin ve C veya C ++ dosyası olarak derlemek için ayarları değiştirin. Örneğin MSVC'de "Yapılandırma Özellikleri-> Genel" bölümündeki "Öğe Türü" ayarını değiştirirsiniz.


1

Böyle bir aracın var olduğunu düşünmüyorum, ancak başka bir cevap beni çürütürse mutlu olurum.

Böyle bir araç yazma sorunu çok kolayca yanlış bir sonuç rapor olmasıdır, bu yüzden böyle bir aracın net avantajı sıfıra yakın olacağını tahmin ediyorum.

Böyle bir aracın çalışabilmesinin tek yolu, sembol tablosunu yalnızca işlediği başlık dosyasının içeriğine sıfırlayabilmesidir, ancak bir kütüphanenin harici API'sını oluşturan başlıkların gerçek bildirimleri temsil ettiği sorunuyla karşılaşırsınız. iç başlıklar.
Örneğin <string>, GCC libc ++ uygulamasında hiçbir şey bildirilmez, ancak gerçek bildirimleri içeren bir grup dahili üstbilgi bulunur. Araç, sembol tablosunu yalnızca <string>kendi başına bildirilen şeye sıfırlarsa , bu hiçbir şey olmaz.
Aracın #include ""ve arasında ayrım yapmasını sağlayabilirsiniz #include <>, ancak harici bir kitaplığın #include ""API'sına dahili üstbilgilerini eklemek için kullandığı durumlarda bu size yardımcı olmaz .


1

bunu #Pragma oncebaşaramaz mı? Bir şeyi doğrudan veya zincirleme eklemeler aracılığıyla istediğiniz kadar ekleyebilirsiniz ve #Pragma onceher birinin yanında bir tane olduğu sürece başlık yalnızca bir kez dahil edilir.

Onu uygulamak için, belki de sadece derlemek için her başlığı bir kukla ana işlev ile tek başına içeren bir inşa sistemi oluşturabilirsiniz. #ifdefzinciri, bu test yöntemiyle en iyi sonuçları içerir.


1

Başlık dosyalarını her zaman CPP dosyasına ekleyin. Bu sadece derleme süresini önemli ölçüde kısaltmakla kalmaz, aynı zamanda önceden derlenmiş üstbilgilere gitmeye karar verirseniz size çok fazla sorun kazandırır. Deneyimlerime göre, pratikte ileri bildirimler sorununu bile yapmaya değer. Kuralı yalnızca gerektiğinde bozun.


Bunun "derleme süresini nasıl önemli ölçüde kısaltacağını" açıklayabilir misiniz?
Mawg, Monica'yı

1
Bu, her derleme biriminin (CPP dosyası) derleme zamanında en az dahil edilen dosyaları almasını sağlar. Aksi takdirde, H dosyalarına dahil ederseniz, yanlış bağımlılık zincirleri hızlı bir şekilde oluşur ve her derlemeyle birlikte tüm içerikleri çekersiniz.
Gvozden

Dahil korumaları ile "quananbtly" quesiton olabilir, ama (bu inlcude gauards keşfetmek için) disk erişimi "yavaş" olduğunu varsayalım, bu yüzden noktası ortadan kalkacaktır.
Açıkladığın

0

Bu sözleşmenin hem avantajları hem de dezavantajları olduğunu söyleyebilirim. Bir yandan, .cpp dosyanızın tam olarak ne olduğunu bilmek güzel. Öte yandan, içerme listesi kolayca saçma bir boyuta büyüyebilir.

Bu kuralı teşvik etmenin bir yolu kendi başlıklarınıza bir şey eklemek değil, yalnızca .cpp dosyalarına bir şey eklemektir. Ardından, açık bir şekilde bağımlı olduğu tüm diğer başlıkları eklemediğiniz sürece, başlığınızı kullanan herhangi bir .cpp dosyası derlenmez.

Muhtemelen burada bazı makul tavizler vardır. Örneğin, standart kitaplık başlıklarını kendi başlıklarınıza dahil etmenin uygun olup olmadığına karar verebilirsiniz, ancak artık yok.


3
Eğer başlıkları dahil bırakırsanız, sipariş eklemek önemli olmaya başlar ... ve kesinlikle bundan kaçınmak istiyorum.
M. Dudley

1
-1: Bir bağımlılık kabusu yaratır.
Xh

1
@ M.Dudley, Dediğim gibi avantajları ve dezavantajları var.
Dima
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.