C / C ++ 'daki gereksiz # tespitler?


289

Sık sık bir dosyanın üstbilgiler bölümünün her zaman büyüyüp büyüdüğünü ancak hiçbir zaman küçülmediğini görüyorum. Bir kaynak dosya ömrü boyunca sınıflar taşınmış ve yeniden düzenlenmiş olabilir ve #includesorada ve artık olması gerekmeyen oldukça az sayıda olması mümkündür . Onları orada bırakmak sadece derleme süresini uzatır ve gereksiz derleme bağımlılıkları ekler. Hangisinin hala gerekli olduğunu anlamaya çalışmak oldukça sıkıcı olabilir.

Gereksiz #include yönergelerini algılayabilen ve hangilerini güvenle kaldırabileceğimi önerebilen bir tür araç var mı?
Tüysüz bunu yapabilir mi?



1
Bağlantılı soru, özellikle Visual Studio'yu kullanarak Windows'daki sorunu ele alıyor gibi görünüyor.
D'Nabre

7
Yinelenen özellikle Visual Studio'yu kullanmakla ilgili olduğu için bunu yeniden açmak için oylama yapın.
Drew Dormann

Yanıtlar:


42

Otomatik değil, ancak doxygen#included dosyalar için bağımlılık diyagramları üretecektir . Onları görsel olarak gözden geçirmeniz gerekecek, ancak neyi kullandığını gösteren bir resim elde etmek için çok yararlı olabilirler.


5
Bu zincirleri görmek için harika bir yoldur .. A -> B -> C -> D ve A -> D'yi görmek artıklığı ortaya çıkarır.
Tom

34
@Tom: Bu korkunç bir Fikir: Birincisi Bu içerme gerekip gerekmediğini göstermez ve ikinci olarak, içerilenler listesi gelecekte değişebilecek dolaylı içeriklere bağlı olmamalıdır (Gereksiz içerikler genellikle böyle bir şey değildir. zaten büyük bir sorun, korumaları ve derleyici sihri dahil), ancak dosyada gerçekte hangi sınıfların / işlevlerin kullanıldığı (Derleyiciniz örneklenmemiş binlerce satır koddan geçmek zorunda kalmamalıdır)
MikeMB

@albert, bunun ekran görüntülerini ekleyebilir ve doxygen çıktısında nereye tıklanacağını kısaca açıklayabilir misiniz?
Gabriel Staples

@GabrielStaples Bu benim cevabım değil, bu yüzden ona bilgi eklemek istemiyorum. Sadece bağlantı düzeltildi (söz konusu barındırma yeri olarak durdu / kullanılmaya el konuldu).
albert

177

Google'ın cppclean (bağlantılar: indirmek , dokümantasyon ) C ++ sorunların birkaç kategori bulabilirsiniz ve artık gereksiz #includes bulabilirsiniz.

Bir Clang tabanlı aracı da yok, dahil-ne-sen kullanımlık yapabilmesidir. ne kullandığınızı içermek, ileri bildirimler bile önerebilir (bu nedenle #incit eklemeniz gerekmez) ve isteğe bağlı olarak #includes'inizi sizin için temizleyebilirsiniz.

Eclipse CDT'nin şu anki sürümleri de bu işlevselliğe sahiptir: Kaynak menüsünün altına girip İçerir Düzenle'yi tıklamak # içerdiklerinizi alfabetik hale getirecek, Eclipse'nin doğrudan dahil etmeden kullandığınızı düşündüğü başlıkları ekleyecek ve içermediği başlıkları yorumlayacaktır. ihtiyacın olduğunu düşünmüyorum. Ancak bu özellik% 100 güvenilir değildir.


2
Şimdi öyle. Sadece kullanmaya başladım. Burada notuma bakın. stackoverflow.com/questions/1301850/…
Chance

1
Cppclean deposu kapalı, şimdi buradan edinebilirsiniz: bitbucket.org/robertmassaioli/cppclean (orijinal site yine de bazı örnek kullanım için hala yararlıdır)
Nick

3
Bağlantıyı sürdürülen bir cppclean çatalına güncelledim: github.com/myint/cppclean
BenC

1
Cppclean'ın bunları cpp dosyalarında değil, yalnızca başlık dosyalarında bulduğunu unutmayın: "Gereksiz # başlık dosyalarına dahil edilmez".
Zitrax

1
@wizurd - Eclipse CDT'deki son gelişmelere ayak uydurmadım, ama sanmıyorum. iwyu tam ve nispeten yavaştır. Eclipse CDT'nin analizi hızlı (etkileşimli) ve test ettiğimde daha az doğru.
Josh Kelley

65

Ayrıca , benzer bir sorunu çözen ne kullandığınızı da ekleyin .


6
IMHO bu cevabın çok daha fazla oyuna ihtiyacı var, çünkü karışıklıklar bir kez çalışıldığında Google'ın IWYU aracı bu görev için kesin bir araç olacak.
Dan Olson

5
sudo apt-get install iwyu
Andrew Wagner

Harika görünüyor - iki cep telefonu ile 1) son güncelleme Şubat 2106 2) Gogole, OP'nin istediği C değil, sadece C ++ için kullanıyorlar.
Mawg, Monica'yı

Kullanıcının nasıl kullanması gerektiğini biraz açıklayabilir misiniz? README, python betiğinin çıktısını neyin içerdiği konusunda çok net değil.
Kralın şakası

Bunu kullanıyorum, ancak her zaman% 100 doğru değil. Belki% 70 kez doğru önerilerde bulunur.
InQusitive

25

Gereksiz içeriklerin algılanmasındaki sorun, sadece bir tür bağımlılık denetleyicisi olamamasıdır. Gereksiz bir ekleme, derlemeye hiçbir değer sağlamayan ve diğer dosyaların bağımlı olduğu başka bir öğeyi değiştirmeyen bir dosyadır . Başlık dosyasının bir derlemeyi değiştirmesinin birçok yolu vardır, örneğin bir sabit tanımlayarak, kullanılmış bir makroyu yeniden tanımlayarak ve / veya silerek, adın aramasını bir şekilde aşağıya doğru değiştiren bir ad alanı ekleyerek. Ad alanı gibi öğeleri algılamak için bir ön işlemciden çok daha fazlasına ihtiyacınız var, aslında neredeyse tam bir derleyiciye ihtiyacınız var.

Lint daha çok bir stil denetleyicisidir ve kesinlikle bu tam kapasiteye sahip olmayacaktır.

Bence gereksiz bir eklentiyi tespit etmenin tek yolunu suitleri kaldırmak, derlemek ve çalıştırmaktır.


8
Dahil etme dosyaları iyi düzenlenmişse bunların hiçbiri sorun olmayacaktır. B dosyasından önce A dosyasını eklemeniz gerekirse, yanlış yapıyorsunuz (ve yanlış yaptıkları projelerde çalıştım).
David Thornley

9
@David, evet ama doğru yapmadan önce devs yıllarına bağlıdır. Olasılıkların evi tercih ettiğini kesin olarak söyleyebilirim, sen değil :(
JaredPar

Evet, ancak genellikle bir programı değiştirirken bunu anlıyorum ve aniden bir derleme hatası (şanslıysam) veya belirsiz bir hata var. Bu, #include dosyalarını en azından uzun vadede dürüst tutuyor gibi görünüyor.
David Thornley

Tam tersini söyleyebilirim. Tek ihtiyacınız olan bir tip bağımlılığı denetleyicisi. Buna göre düzenlemeler yaptıktan sonra derlenmeyebilir, ancak bunlar yine de ele alınması gereken problemlerdir.
Benoît

1
@Benoit, programınızın anlamını derleyen ancak anlamsal olarak değiştiren bir sınıf sorununu görmezden gelirsiniz. Bir dosyadaki # tanımının başka bir dosyadaki #if dalını nasıl değiştirebileceğini düşünün. Bir başlığı kaldırmak yine de bunun farklı sonuçlarla derlenmesine izin verebilir
JaredPar

15

PCLint'in bunu yapacağını düşündüm , ama bakmamın üzerinden birkaç yıl geçti. Kontrol edebilirsin.

Bu bloga baktım ve yazar, PCLint'i kullanılmayan içerikleri bulmak için yapılandırma hakkında biraz konuştu. Bir göz atmaya değer olabilir.


İyi bulmak! Bunu kullanmam gerekecek.
crashmstr

4
PCLint'i düzenli olarak kullanıyorum ve bana kullanılmayan başlıkları anlatıyor. #İnclude başlığını yorumlamaya dikkat ediyorum ve başlığın gerçekten kullanılmadığından emin olmak için yeniden derleyin ...
Harold Bamford

Onay için teţekkürler Harold.
itsmatt

5
çok pahalı. kitleler için uygun bir araç değil.

7

CScout yeniden düzenleme tarayıcı gereksiz C (ne yazık ki değil C ++) kodu yönergeleri içermesi algılayabilir. Bu dergi makalesinde nasıl çalıştığına dair bir açıklama bulabilirsiniz .


5

Tek bir #include yönergesini silen, projeleri derleyen ve #include içindeki adı günlüğe kaydeden ve derleme hatalarının oluşmaması durumunda kaldırıldığı dosyayı hızlı bir komut dosyası yazabilirsiniz.

Gece boyunca çalışmasına izin verin ve ertesi gün kaldırabileceğiniz% 100 doğru dosya listesine sahip olacaksınız.

Bazen kaba kuvvet sadece çalışır :-)


edit: ve bazen değil :-). İşte yorumlardan biraz bilgi:

  1. Bazen iki başlık dosyasını ayrı olarak kaldırabilirsiniz, ancak ikisini birlikte kaldıramazsınız. Çözüm, çalışma sırasında başlık dosyalarını kaldırmak ve geri getirmektir. Bu, güvenli bir şekilde kaldırabileceğiniz dosyaların bir listesini bulur, ancak bu algoritmanın bulamayacağı daha fazla dosya içeren bir çözüm olabilir. (kaldırılacak dosyaları dahil etme alanı üzerinde açgözlü bir arama.
  2. Bazı #ifdef'lere bağlı olarak farklı şekilde yeniden tanımlanmış bazı makrolarınız varsa, davranışta küçük değişiklikler olabilir. Bence bunlar çok nadir vakalardır ve yapının bir parçası olan Birim Testleri bu değişiklikleri yakalamalıdır.

1
Buna dikkat edin - her ikisinin de bir şey tanımı içeren iki başlık dosyası olduğunu varsayalım. İkisini de kaldırabilirsiniz, ancak ikisini birden kaldıramazsınız. Kaba kuvvet yaklaşımınızda biraz daha ayrıntılı olmanız gerekir.
Dominic Rodger

Belki bu demek istediniz, ancak tek bir eklemeyi kaldıran ve başarıyla kaldırılmışsa son kaldırılanı bırakan bir komut dosyası hile yapacaktır.
Dominic Rodger

1
Kötü bir fikir. # Başlık dosyası sabit bir BLAH tanımlarsa ve başka bir başlık dosyası #ifdef BLAH'ı denetlerse, ilk başlık dosyasını kaldırmak yine de başarılı bir şekilde derlenebilir ancak davranışınız değişmiştir.
Graeme Perrow

1
Bu, sistem başlıkları ile ilgili sorunlara da neden olabilir, çünkü farklı uygulamalar #include <vector> içinde farklı şeyler içerebilir. Bir derleyiciye bağlı kalsanız bile, başlıklar farklı sürümlere göre değişebilir.
David Thornley

2
Bu, gerçekten ihtiyacınız olan başlığı içeren bir başlık eklediğiniz durumları bulamaz.
bk1e

5

Buraya gönderi yaptığım için üzgünüm, insanlar genellikle yorumları genişletmiyor.

Crashmstr hakkındaki yorumumu kontrol edin, FlexeLint / PC-Lint bunu sizin için yapacak. Bilgilendirici mesaj 766. Kılavuzumun 11.8.1 bölümü (sürüm 8.0) bunu tartışıyor.

Ayrıca, bu önemlidir, mesaj kaybolana kadar yinelemeye devam edin . Başka bir deyişle, kullanılmayan üstbilgileri kaldırdıktan sonra tiftiği yeniden çalıştırın, bazı gereksiz üstbilgileri kaldırdığınızda daha fazla üstbilgi dosyası "gereksiz" olabilir. (Aptalca gelebilir, yavaşça okuyabilir ve ayrıştırabilir, mantıklı olabilir.)


Ne demek istediğini tam olarak biliyorum ve tepkim "Ewwww" idi. Böyle koddan nefret ediyorum.
David Thornley

5

Sorduğunuz şeyi başaran tam teşekküllü bir araç bulamadım. Kullandığım en yakın şey , başlık içerme ağacınızı grafik haline getiren IncludeManager , böylece yalnızca tek bir dosyada yer alan üstbilgiler ve dairesel başlık eklemelerini görsel olarak tespit edebilirsiniz.


4

Flexelint'i (PC-Lint'in unix sürümü) kullanmayı denedim ve biraz karışık sonuçlar aldım. Bu muhtemelen çok büyük ve düğümlü bir kod tabanı üzerinde çalışıyorum çünkü. Kullanılmadığı bildirilen her dosyayı dikkatlice incelemenizi öneririz.

Ana endişe yanlış pozitiftir. Aynı üstbilginin birden fazla eklenmesi gereksiz bir üstbilgi olarak bildirilir. Flexelint, başlığın hangi satıra dahil edildiğini veya daha önce nereye dahil edildiğini size söylemediğinden bu durum kötüdür.

Otomatik araçların bunu yanlış yapmasının yollarından biri:

A.hpp'de:

class A { 
  // ...
};

B.hpp'de:

#include "A.hpp

class B {
    public:
        A foo;
};

C.cpp'de:

#include "C.hpp"  

#include "B.hpp"  // <-- Unneeded, but lint reports it as needed
#include "A.hpp"  // <-- Needed, but lint reports it as unneeded

Flexelint'in mesajlarını körü körüne takip ederseniz #include bağımlılıklarınızı boğacaksınız. Daha fazla patolojik vaka var, ancak temel olarak en iyi sonuçlar için başlıkları kendiniz kontrol etmeniz gerekecek.

İçeriden Blog Oyunları'ndan Fiziksel Yapı ve C ++ ile ilgili bu makaleyi tavsiye ederim . #İnclude karmaşasını temizlemek için kapsamlı bir yaklaşım öneriyorlar:

Kuralları

İşte Lakos'un kitabından, dosyalar arasındaki fiziksel bağımlılıkların sayısını en aza indiren, damıtılmış bir kılavuz seti. Onları yıllardır kullanıyorum ve sonuçlardan hep çok memnun kaldım.

  1. Her cpp dosyası önce kendi başlık dosyasını içerir. [Kesik]
  2. Başlık dosyası, ayrıştırmak için gerekli tüm başlık dosyalarını içermelidir. [Kesik]
  3. Bir üstbilgi dosyası, ayrıştırmak için gereken en az sayıda üstbilgi dosyasına sahip olmalıdır. [Kesik]

Lakos'un kitabı, derleyici teknolojisi hakkındaki eski gözlemlerinin yanı sıra eğitim için harikadır.
Tom

4

Eclipse CDT kullanıyorsanız deneyebileceğiniz http://includator.com (bu yazının yazıldığı anda) beta test için ücretsizdir ve otomatik gereksiz #includes kaldırır veya eksik olanları ekler hangi. FlexeLint veya PC-Lint'e sahip olan ve Elicpse CDT kullanan kullanıcılar için http://linticator.com bir seçenek olabilir (beta testi için de ücretsiz). Lint'in analizini kullanırken, gereksiz #include ifadelerini otomatik olarak kaldırmak için hızlı düzeltmeler sağlar.


Bunun nedeni defter tutma bölümümüzün daha az tutar faturalayamamasıdır. Tasarruf edebileceğiniz zamanı sayarsanız mantıksız değildir. Bir kez, fiyatı önemli ölçüde azaltabileceğimiz kredi kartı ödemeleri alma yeteneğine sahibiz. Başka bir seçenek, geliştirme çabalarımız için bir sponsor olacaktır. Finansman modelimiz araştırma çalışmalarımızı finanse etmek için kar elde etmemizi gerektirir. Lisansları çok daha ucuza satmaktan mutlu olurum ama yapamam. Belki CDT'ye katkıda bulunacağız ve ücretsiz olarak alabilirsiniz, ama bir şekilde finanse etmeliyim. Unuttum, ücretsiz deneyebilirsiniz!
PeterSom

2

Bu makalede , # okslude'un Doxygen çözümlemesini kullanarak kaldırma tekniğini açıklamaktadır. Bu sadece bir perl betiği, bu yüzden kullanımı oldukça kolay.


1
Komut dosyası kaldırılacak bazı içerikler bulur, ancak kaldırılamayan birçok içerik de sağlar. Görünüşe göre sınıf enumunu desteklemiyor, makro ve bazen de ad alanı ile kötü bir zaman geçiriyor gibi görünüyor.
Baptiste Wicht



1

İki tür gereksiz #include dosyası vardır:

  1. Modül (.c, .cpp) tarafından gerçekten gerekli olmayan bir başlık dosyası
  2. Bir başlık dosyası modül tarafından gereklidir, ancak birden fazla, doğrudan veya dolaylı olarak dahil edilir.

Deneyimlerimde, bunu tespit etmek için iyi çalışan 2 yol var:

  • gcc -H veya cl.exe / showincludes (2. sorunu çözün)

    Gerçek dünyada, eğer Makefile'in tümü CFLAGS seçeneklerini geçersiz kılmazsa, CFLAGS = -H yapmadan önce dışa aktarabilirsiniz. Ya da kullandığım gibi, her $ (CC) ve $ (CXX) çağrısına zorla -H seçenekleri eklemek için bir cc / g ++ sarmalayıcısı oluşturabilirsiniz. ve sarmalayıcı dizinini $ PATH değişkenine ekleyin, ardından make'iniz size wrapper komutunu kullanır. Tabii ki ambalajınız gerçek gcc derleyicisini çağırmalıdır. Makefile'niz doğrudan gcc kullanıyorsa bu hilelerin değişmesi gerekir. $ (CC) veya $ (CXX) yerine veya zımni kurallara göre.

    Komut satırıyla ayarlayarak tek bir dosyayı da derleyebilirsiniz. Ancak tüm proje için başlıkları temizlemek istiyorsanız. Tüm çıktıları şu yollarla yakalayabilirsiniz:

    temizle

    marka 2> & 1 | tee sonuç.txt

  • PC-Lint / FlexeLint (sorunu hem 1 hem de 2'de çözün)

    + e766 seçeneklerini eklediğinizden emin olun, bu uyarı aşağıdakilerle ilgilidir: kullanılmayan başlık dosyaları.

    pclint / flint -vf ...

    Bu pclint çıktı başlık dosyaları dahil neden olacak, iç içe başlık dosyaları uygun girintili olacaktır.


1

Bu tartışmayı sonlandırmak için: c ++ önişlemcisi tamamlanıyor. İçermenin gereksiz olup olmadığı anlamsal bir özelliktir. Bu nedenle, Rice'ın teoreminden, bir içerme işleminin gereksiz olup olmadığı kararsızdır. Bir içerme gereksizdir (her zaman doğru) bir program olamaz.


5
"Her zaman doğru" bir çözüm mü istedim? Bu cevap tartışma için çok verimli değil.
shoosh

1
Peki böyle bir programın uğraşması gereken sorunları tartışan çok sayıda yazı vardı. Görevim, tartışmanın bu kısmına kesin ve doğru bir cevap veriyor. Biri için bunu sevmezdim, eğer bir program bana söylerse, #include'u güvenle kaldırabilirim ve sonra kodum artık derlenmez. (veya daha kötüsü - hala derler, ancak farklı bir şey yapar). Böyle bir program bu riski taşır.
Algoman

4
Bunun ne kadar zor olacağı ve bir engeli ya da diğerini nasıl çözebileceğine dair tüm ŞARTNAMELER arasında, size sadece% 100 doğru cevabı verdim. Bunun üretken olmadığını söylemek oldukça küstah buluyorum ...
Algoman

1
Rice'ın teoreminin "Verilen bir programın bu gereksiz içeren sorunu çözüp çözmediğini her zaman kontrol edebilecek bir program olamaz" diye hatırladım. Gereksiz içerikler sorununu çözen birkaç program olabilir.
Zhe Yang

1
Şahsen ben @ Algoman'ın girişini çok yararlı buldum. bu sorunun ne kadar zor olduğunu anlamamı sağlıyor.
bogardon


0

Gimpel Yazılımları PC Lint'i , bir ekleme dosyasının bir derleme birimine birden çok kez dahil edildiğini bildirebilir , ancak aradığınız şekilde gerekli olmayan dosyaları içeremez.

Düzenleme: Olabilir. Mattinin cevabını görün


Bundan emin misin ? C ++ kodunda birkaç yıl içinde FlexeLint (PCL ile aynı) kullanmadım, ancak son zamanlarda C kodunda bile, kullanılmayan başlık dosyaları hakkında birkaç mesaj (sanırım kod 766?) Olduğunu yemin edebilirim. Yeni kontrol edildi (v8.0), bkz. Bölüm 11.8.1. kılavuz.
Dan

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.