Bir C kaynak dosyasını diğerine mi dahil ediyorsunuz?


Yanıtlar:


113

Doğru kullanıldığında bu yararlı bir teknik olabilir.

Oldukça küçük bir genel arabirime ve çok sayıda yeniden kullanılamaz uygulama koduna sahip karmaşık, performans açısından kritik bir alt sisteminiz olduğunu varsayalım. Kod birkaç bin satıra, yüz kadar özel işleve ve epeyce özel veriye kadar çalışır. Önemsiz olmayan gömülü sistemlerle çalışıyorsanız, muhtemelen bu durumla yeterince sık başa çıkarsınız.

Çözümünüz muhtemelen katmanlı, modüler ve ayrıştırılmış olacaktır ve bu yönler, alt sistemin farklı bölümlerini farklı dosyalarda kodlayarak yararlı bir şekilde temsil edilebilir ve güçlendirilebilir.

C ile bunu yaparak çok şey kaybedebilirsiniz. Hemen hemen tüm araç zincirleri, tek bir derleme birimi için yeterli optimizasyon sağlar, ancak extern olarak bildirilen herhangi bir şey hakkında çok kötümserdir.

Her şeyi tek bir C kaynak modülüne koyarsanız, şunu elde edersiniz -

  • Performans ve kod boyutu iyileştirmeleri - birçok durumda işlev çağrıları satır içi olacaktır. Satır içi olmadan bile derleyicinin daha verimli kod üretme fırsatları vardır.

  • Bağlantı düzeyinde veri ve işlev gizleme.

  • Ad alanı kirliliğinden ve bunun sonucundan kaçınma - daha az kullanışsız adlar kullanabilirsiniz.

  • Daha hızlı derleme ve bağlantı.

Ancak konu bu dosyayı düzenlemek olduğunda da kötü bir karmaşa yaşarsınız ve zımni modülerliği kaybedersiniz. Bu, kaynağı birkaç dosyaya bölerek ve bunları tek bir derleme birimi oluşturmak için dahil ederek aşılabilir.

Bununla birlikte, bunu doğru bir şekilde yönetmek için bazı kurallar koymanız gerekir. Bunlar bir dereceye kadar alet zincirinize bağlı olacaktır, ancak bazı genel işaretçiler şunlardır:

  • Genel arayüzü ayrı bir başlık dosyasına koyun - bunu yine de yapmalısınız.

  • Tüm yardımcı .c dosyalarını içeren bir ana .c dosyasına sahip olun. Bu, genel arabirim kodunu da içerebilir.

  • Özel üstbilgilerin ve kaynak modüllerin harici derleme birimleri tarafından dahil edilmediğinden emin olmak için derleyici korumalarını kullanın.

  • Tüm özel veriler ve işlevler statik olarak beyan edilmelidir.

  • .C ve .h dosyaları arasındaki kavramsal farkı koruyun. Bu, mevcut kurallardan yararlanır. Aradaki fark, başlıklarınızda çok fazla statik bildirim olacak olmasıdır.

  • Araç zinciriniz bunu yapmamak için herhangi bir sebep belirtmiyorsa, özel uygulama dosyalarını .c ve .h olarak adlandırın. İçerme korumalarını kullanırsanız, bunlar kod üretmez ve yeni adlar getirmez (bağlantı sırasında bazı boş bölümlerle karşılaşabilirsiniz). En büyük avantajı, diğer araçların (örn. IDE'ler) bu dosyaları uygun şekilde ele almasıdır.


1
+1 Bu hala gerçektir, daha iyi derleyiciler bu yöntemi zamanla geçersiz kılacaktır. Bağlantı zamanı optimizasyonlu GCC 4.5 bu yolda büyük bir adımdır.
u0b34a0f6ae

Bunu yapan pek çok program gördüm ve kodlarını yeniden kullanmaya çalışırken sinirlerimi bozuyor. Bunu neden yaptıklarını açıkladığınız ve bir gardiyan kullanılmasını önerdiğiniz için teşekkür ederiz (ki bu genellikle yapılmaz).
Joey Adams

C51 için gömülü geliştirmede, extern ve çoklu C dosyalarının kullanılması baş ağrısından başka bir şeye neden olmadı. Zamanımı geri almak için bir C dosyasına diğerlerinin de dahil olmasına geçiyorum.
mahesh

Kayıtlar için: GCC, farklı çeviri birimlerinde optimizasyonu destekler , bağlantı süresi optimizasyonu hakkındaki bu SO iş parçacığına ve GCC kılavuz bölümüne bakın .
Twonky

60

tamam mı? evet, derlenecek

tavsiye edilir mi no - .c dosyaları, derlemeden sonra (bağlayıcı tarafından) yürütülebilir dosyaya (veya kitaplığa) bağlanan .obj dosyalarına derlenir; bu nedenle, bir .c dosyasını diğerine eklemeye gerek yoktur. Bunun yerine muhtemelen yapmak isteyeceğiniz şey, diğer .c dosyasında bulunan işlevleri / değişkenleri listeleyen ve .h dosyasını içeren bir .h dosyası oluşturmaktır.


14
Ayrıca, derlese bile, #included .c dosyası da derlenmişse ve iki nesne dosyası birbirine bağlanmışsa bağlantı kuramayabileceğini de belirtmek gerekir - birden çok tanımlı semboller elde edebilirsiniz.
Nick Meyer

1
Küçük bir soru. Bir struct + yöntemini ve ayrıca bunları tanımlamak için karşılık gelen .c dosyasını bildiren bir başlık dosyam var. Bu yöntem yapıyı parametre olarak alırsa, .c dosyasını ana yöntemin tanımlandığı başka bir .c dosyasına dahil etmekten nasıl kaçınırım?
stdout

12

Hayır.

Oluşturma ortamınıza bağlı olarak (belirtmezsiniz), tam olarak istediğiniz şekilde çalıştığını görebilirsiniz.

Ancak, * .c'yi derlemeyi bekleyen birçok ortam (hem IDE'ler hem de birçok el yapımı Makefile) vardır - bu durumda büyük olasılıkla yinelenen semboller nedeniyle bağlayıcı hatalarıyla karşılaşacaksınız.

Kural olarak bu uygulamadan kaçınılmalıdır.

Kaynağı #include etmeniz gerekiyorsa (ve genellikle bundan kaçınmanız gerekiyorsa), dosya için farklı bir dosya soneki kullanın.


9

Ekibimin .c dosyalarını eklemeye karar verdiği bir durumu paylaşacağımı düşündüm. Mimarimiz büyük ölçüde bir mesaj sistemiyle ayrıştırılan modüllerden oluşur. Bu ileti işleyicileri geneldir ve işlerini yapmak için birçok yerel statik işçi işlevini çağırır. Bu özel uygulama kodunu kullanmanın tek yolu dolaylı olarak genel mesaj arabirimi aracılığıyla olduğundan, sorun, birim test durumlarımızı kapsamaya çalışırken ortaya çıktı. Bazı işçi fonksiyonları dizinin derinliklerinde olduğu için, bu, uygun kapsama alanı elde etmek için bir kabusa dönüştü.

.C dosyalarının dahil edilmesi, test etmede ilginç olduğumuz makinedeki dişliye ulaşmamız için bize bir yol sağladı.


6

Linux'taki gcc derleyicisini iki c dosyasını bir çıktıda birbirine bağlamak için kullanabilirsiniz. İki c dosyanız olduğunu varsayalım; biri 'main.c' ve diğeri 'support.c'. Dolayısıyla, bu ikisini bağlama komutu

gcc main.c support.c -o main.out

Bununla iki dosya tek bir çıktıya bağlanacaktır main.out Çıkışı çalıştırmak için komut olacaktır

./main.out

Support.c dosyasında bildirilen main.c'de bir işlevi kullanıyorsanız, bunu main içinde ayrıca extern depolama sınıfını da kullanarak bildirmelisiniz.


5

Dosyanın uzantısı çoğu C derleyicisi için önemli değildir, bu yüzden işe yarayacaktır.

Bununla birlikte, makefile veya proje ayarlarınıza bağlı olarak, dahil edilen c dosyası ayrı bir nesne dosyası oluşturabilir. Bağlanırken bu çift tanımlı sembollere yol açabilir.


3

.C veya .CPP dosyalarını diğer kaynak dosyalara düzgün bir şekilde dahil edebilirsiniz. IDE'nize bağlı olarak, genellikle dahil edilmesini istediğiniz kaynak dosya özelliklerine bakarak, genellikle üzerine sağ tıklayıp özellikleri tıklayarak ve derleme / bağlantı / derlemeden dışlama veya herhangi bir seçeneğin işaretini kaldırarak / kontrol ederek çift bağlantıyı önleyebilirsiniz. olabilir. Ya da dosyayı projenin kendisine dahil edemezsiniz, bu nedenle IDE onun varlığını bile bilmeyecek ve derlemeye çalışmayacaktır. Ve makefiles ile dosyayı derlemek ve bağlamak için içine koymazsınız.

DÜZENLEME: Üzgünüm, diğer cevaplara cevap vermek yerine cevap verdim :(


1

C dili bu tür bir #include'ı yasaklamaz, ancak ortaya çıkan çeviri biriminin yine de geçerli olması gerekir C.

.Prj dosyasıyla hangi programı kullandığınızı bilmiyorum. "Make" veya Visual Studio gibi bir şey kullanıyorsanız veya herhangi bir şey kullanıyorsanız, dosya listesini bağımsız olarak derlenemeyenler olmadan derlenecek şekilde ayarladığınızdan emin olun.


0

C dosyasını başka bir dosyaya eklemek yasaldır, ancak bunu neden yaptığınızı ve neyi başarmaya çalıştığınızı tam olarak bilmediğiniz sürece yapılması tavsiye edilmez.
Neredeyse eminim ki, sorunuzun ardında, topluluğun size hedefinize ulaşmak için daha uygun başka bir yol bulmasının nedenini burada yayınlarsanız (lütfen "neredeyse" kelimesine dikkat edin, çünkü bağlam dikkate alındığında çözüm bu olabilir. ).

Bu arada sorunun ikinci bölümünü kaçırdım. C dosyası başka bir dosyaya dahil edilirse ve aynı zamanda projeye dahil edilirse, muhtemelen nesnelerin bağlanmasının nedeninin yinelenen sembol problemiyle karşılaşacaksınız, yani aynı işlev iki kez tanımlanacaktır (hepsi statik olmadıkça).


-6

bunun gibi başlık eklemelisin

#include <another.c>

not: her iki dosya da aynı yere yerleştirilmelidir

Bunu ATMEGA mikro denetleyicileri için AVR codevison'da kullanıyorum ve gerçekten çalışıyorum ancak normal C dili dosyasında çalışmıyor

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.