Neden bazı C programları büyük bir kaynak dosyaya yazılmıştır?


88

Örneğin , geçmişten gelen SysInternals aracı "FileMon", kaynak kodu tamamen 4.000 satırlık bir dosyada bulunan bir çekirdek modu sürücüsüne sahiptir. Şimdiye kadar yazılmış ilk ping programı için de aynı (~ 2.000 LOC).

Yanıtlar:


143

Birden fazla dosya kullanmak her zaman ek idari ek yük gerektirir. Bir derleme ve / veya ayrılmış derleme ve bağlama aşamaları ile makefile oluşturmak, farklı dosyalar arasındaki bağımlılıkların doğru yönetildiğinden emin olmak, kaynak kodun e-posta veya indirme yoluyla daha kolay dağıtılması için bir "zip" betiği yazmak vb. üzerinde. Günümüzde modern IDE'ler genellikle bu yükün çoğunu üstlenir, ancak ilk ping programının yazıldığı sırada, bu tür bir IDE bulunmadığından oldukça eminim. Ve ~ 4000 LOC kadar küçük dosyalar için, sizin için birden fazla dosyayı iyi yöneten bir IDE olmadan, söz konusu ek yük ile birden fazla dosya kullanmanın yararları arasındaki ilişki insanların tek dosya yaklaşımı için bir karar vermesine neden olabilir.


9
“Ve ~ 4000 LOC kadar küçük dosyalar için…” Şu anda bir JS dev olarak çalışıyorum. Sadece 400 satırlık bir dosya kodum olduğunda, bunun ne kadar büyük olduğu konusunda endişeliyim! (Ama projemizde onlarca ve onlarca
Kevin

36
@Kevin: Kafamdaki bir saç çok az, çorbamdaki bir saç çok fazla ;-) JS çoklu dosyalarında AFAIK "modern bir IDE'siz C" deki kadar idari ek yüke neden olmuyor.
Doktor Brown

4
@Kevin JS, oldukça farklı bir canavar. JS, bir kullanıcı bir web sitesi her yüklediğinde ve tarayıcıları tarafından önbelleğe alınmamışsa, son kullanıcıya iletilir. C kodun yalnızca bir kez iletilmesi gerekir, sonra diğer uçtaki kişi onu derler ve derlenir (açıkçası istisnalar vardır, ancak bu beklenen genel durumdur). Ayrıca C işleri, insanların yorumlarda anlattıkları “4000 satır normaldir” projelerinin çoğu gibi eski kod olma eğilimindedir.
Pharap

5
@Kevin Şimdi gidin ve undercore.js'nin (1700 loc, bir dosya) ve dağıtılan diğer kütüphanelerin sayısız nasıl yazıldığını görün. Javascript, modülerleştirme ve konuşlandırma ile ilgili olarak neredeyse C kadar kötü.
Voo

2
@Pharap Ben kodu dağıtmadan önce Webpack gibi bir şey kullanarak demek istedim . Webpack ile birden fazla dosya üzerinde çalışabilir ve daha sonra bunları bir paket halinde derleyebilirsiniz.
Brian McCutchon

81

Çünkü C modülerleşmede iyi değil. Dağınık (başlık dosyaları ve #includes, harici fonksiyonlar, link-time hataları, vb.) Ve ne kadar fazla modül eklerseniz, o kadar zorlaşır.

Daha modern diller kısmen daha iyi modülerleştirme yeteneklerine sahiptir, çünkü C'nin hatalarından öğrenirler ve kod tabanınızı daha küçük ve daha basit birimlere ayırmayı kolaylaştırırlar. Ancak C ile, aksi halde tek bir dosyada çok fazla kod olarak kabul edilebilecek olanların toplanması anlamına gelse bile, tüm bu sorunlardan kaçınmak veya en aza indirmek faydalı olabilir.


38
C yaklaşımını 'hatalar' olarak tanımlamanın haksızlık olduğunu düşünüyorum; Onlar yapıldığı anda kusursuz ve makul kararlar aldılar.
Jack Aidley

14
Bu modülerleştirme olaylarının hiçbiri özellikle karmaşık değildir. Bu edilebilir yapılan kötü kodlama stili ile komplike, ancak, anlaşılması veya uygulanması zor değil ve hiçbiri "hatalar" olarak sınıflandırılır olabilir. Snowman'ın cevabına göre asıl sebep, birden fazla kaynak dosyadaki optimizasyonun geçmişte çok iyi olmaması ve FileMon sürücüsünün yüksek performans gerektirmesidir. Ayrıca, OP'nin görüşüne aykırı olarak, bunlar özellikle büyük dosyalar değildir.
Graham

8
@Graham 1000 kod satırından büyük olan herhangi bir dosya kod kokusu olarak değerlendirilmelidir.
Mason Wheeler

11
Onun değil haksız @JackAidley hiç sahip bir şey bir hata o anda makul bir karar olduğunu söyleyerek ile özel karşılıklı değil olun. Hatalı bilgiler ve sınırlı bir süre verilen hatalar kaçınılmazdır ve yüzleri kurtarmak için utanç verici şekilde gizlenmemesi veya yeniden sınıflandırılmaması gerektiği öğrenilmelidir.
Jared Smith

8
C'nin yaklaşımının bir hata olmadığını iddia eden herhangi biri, görünüşte on-liner C dosyasının aslında tüm başlıkları olan on-bin liner dosyası olabileceğini anlayamıyor. #. Bu, "wc -l" tarafından verilen satır sayısı ne olursa olsun, projenizdeki her bir dosyanın etkin biçimde en az on bin satır olduğu anlamına gelir. Modülerliğe daha iyi destek, ayrıştırma ve derleme zamanlarını kolayca küçük bir kesime böler
juhist

37

Tarihsel nedenlerin yanı sıra, bunu modern performansa duyarlı yazılımda kullanmanın bir nedeni var. Kodun tümü bir derleme ünitesindeyken, derleyici tüm program optimizasyonlarını yapabilir. Ayrı derleme üniteleriyle, derleyici tüm programı belirli şekillerde optimize edemez (örneğin, belirli bir kodu satırlara yerleştirerek).

Bağlayıcı kesinlikle derleyicinin yapabileceklerine ek olarak bazı optimizasyonlar yapabilir, ancak hepsini yapamaz. Örneğin: modern bağlayıcılar, birden çok nesne dosyasında bile, kayıtsız işlevler seçmede gerçekten iyidir. Başka optimizasyonlar yapabilirler, fakat bir derleyicinin bir fonksiyon içinde yapabilecekleri gibi bir şey yoktur.

Tek kaynaklı bir kod modülünün iyi bilinen bir örneği SQLite'dir. Bunun hakkında daha fazla bilgiyi The SQLite Amalgamation sayfasından öğrenebilirsiniz .

1. Yönetici Özeti

100'den fazla ayrı kaynak dosya "sqlite3.c" adında ve "birleştirilmesi" olarak adlandırılan tek bir büyük C kodu dosyasına birleştirilir. Birleştirme, bir uygulamanın SQLite'yi gömmek için ihtiyaç duyduğu her şeyi içerir. Birleştirme dosyası 180.000'den fazla satır uzunluğunda ve 6 megabayttan daha büyüktür.

Tüm SQLite kodunu tek bir büyük dosyada birleştirmek, SQLite'ın kurulumunu kolaylaştırır - izlenmesi gereken tek bir dosya vardır. Ayrıca tüm kodlar tek bir çeviri biriminde olduğundan, derleyiciler% 5 ile% 10 arasında daha hızlı olan makine koduyla sonuçlanan daha iyi prosedürler arası optimizasyon yapabilir.


15
Ancak, modern C derleyicilerinin birden fazla kaynak dosyasının tümüyle program optimizasyonunu yapabileceğini unutmayın (ilk önce tek tek nesne dosyalarında derlemeseniz de).
Davislor

10
@Davislor Tipik derleme komut dosyasına bakın: derleyiciler bunu gerçekçi şekilde yapmayacaklar.

4
Bir oluşturma komut dosyasını değiştirmek, $(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) $(CFILES)her şeyi tek bir soudce dosyasına taşımaktan çok daha kolaydır . Tüm program derlemesini, insanların profil oluşturma ve hata ayıklama işlemlerini nasıl kapattıklarına benzer şekilde değiştirmemiş olan yeniden derleme işlemini atlayan geleneksel derleme komut dosyasına alternatif bir hedef olarak bile yapabilirsiniz. Her şey bir büyük yığın kaynağındaysa bu seçeneğe sahip değilsiniz. İnsanların alıştığı şey bu değil, ama bunun için hantal bir şey yok.
Davislor

9
@Davislor bütün program optimizasyonu / link-time optimizasyonu (LTO), kodu ayrı ayrı nesne dosyalarına "derlediğinizde" ("derleme" nin sizin için ne anlama geldiğine bağlı olarak) de çalışır. Örneğin, GCC'nin LTO'su ayrıştırma kodu gösterimini, derleme zamanında ayrı ayrı nesne dosyalarına ekleyecek ve bağlantı zamanında, tüm programı yeniden derlemek ve oluşturmak için (aynı zamanda mevcut) nesne kodu yerine birini kullanır. Bu, ilk derleme tarafından oluşturulan makine kodu göz ardı edilse de, ilk önce tek tek nesne dosyalarını derleyen derleme kurulumlarıyla çalışır.
Hayalperest,

8
JsonCpp bugünlerde de bunu yapıyor. Anahtar, geliştirme sırasında dosyaların bu şekilde olmamasıdır.
Orbit'te Hafiflik Yarışları

15

Basitlik faktörüne ek olarak, diğer katılımcı belirtilen, birçok C programı bir kişi tarafından yazılmıştır.

Bireysel ekibiniz olduğunda, kod değişikliklerinde gereksiz çakışmaları önlemek için uygulamayı birkaç kaynak dosyaya bölmek istenir. Özellikle, projede çalışan hem ileri hem de çok küçük programcılar olduğunda.

Bir kişi kendi başına çalışıyorsa, bu sorun değil.

Şahsen ben alışkanlık yapan bir şey olarak işlevine bağlı olarak birden fazla dosya kullanıyorum. Ama bu sadece benim.


4
@OskarSkog Fakat bir dosyayı asla gelecekteki benliğinizle değiştirmeyeceksiniz.
Loren Pechtel

2

Çünkü C89'un inlineişlevleri yoktu . Bu, dosyanızı işlevlere bölmek anlamına gelir, yığında değerlerin itilmesi ve etrafa atlamak yükü. Bu, kodu 1 büyük anahtar ifadesinde (olay döngüsü) uygulamak için bir miktar ek yük ekledi. Ancak bir olay döngüsünün, daha modüler bir çözümden daha verimli (hatta doğru) uygulanması her zaman çok daha zordur. Bu yüzden büyük ölçekli projeler için insanlar modülerleşmeyi tercih ediyor. Ancak tasarımı önceden düşünmüşler ve durumu 1 anahtar ifadesinde kontrol edebiliyorlardı, bunun için seçtiler.

Günümüzde, C'de bile, modülerleştirme için performanstan ödün verilmesine gerek yoktur çünkü C işlevlerinde bile satır içi olabilir.


2
C işlevleri bugünlerde olduğu gibi 89'da satır içi kadar olabilir, satır içi neredeyse hiç kullanılmaması gereken bir şeydir - derleyici neredeyse her durumda sizden daha iyi bilir. Ve bu 4k LOC dosyalarının çoğu, devasa bir işlev değildir; bu, gözle görülür bir performans avantajına sahip olmayacak olan korkunç bir kodlama stilidir.
Voo

@Voo, kodlama stilinden neden bahsettiğinizi bilmiyorum. Savunmuyordum. Aslında, çoğu durumda, botched bir uygulama nedeniyle daha az verimli bir çözümü garanti ettiğini belirtmiştim. Ayrıca bunun kötü bir fikir olduğunu da belirttim, çünkü ölçeklenmiyor (daha büyük projelere). Çok sıkı döngülerde (donanıma yakın ağ kodunda olan şeydir), gereksiz açma / kapama yığınlarını (fonksiyon çağırırken) gereksiz yere itme ve fırlatmanın çalışan programın maliyetini artıracağını söylemiştik. Bu harika bir çözüm değildi. Ama o zamanlar mevcut olan en iyisiydi.
Dmitry Rubanovich

2
Zorunlu not: satır içi anahtar kelimenin, satır içi optimizasyonla yalnızca küçük bir ilgisi vardır. Derleyicinin bu optimizasyonu yapması özel bir ipucu değildir, bunun yerine yinelenen sembollerle bağlantı kurmak zorundadır.
hyde

@Dmitry Mesele şu ki inline, C89 derleyicilerinde hiç bir anahtar kelime olmadığı için satır içi olamaz , çünkü her şeyi tek bir dev fonksiyonda yazmak zorunda kalıyorsunuzdur . Asla inlinebir performans optimizasyonu olarak kullanmamalısınız - derleyici genellikle sizden daha iyi bilecektir (ve anahtar kelimeyi de görmezden gelebilir).
Voo

@Voo: Bir programcı ve derleyici genellikle her biri diğerinin bilmediği bazı şeyleri bilir. inlineAnahtar kelime in-line optimizasyonlar için olsun veya olmasın sorusu daha önemli olduğu bağlayıcı ilgili anlambilim içeriyor, ancak bazı uygulamalar içinde astar kontrol etmek ve bu tür şeyler bazen çok önemli olabilir diğer direktiflerini var. Bazı durumlarda, bir işlev kaplamaya değmeyecek kadar büyük gibi görünebilir, ancak sabit katlama boyutu ve yürütme süresini neredeyse hiçbir şeye indirgeyemez.
Astarı

1

Bu, henüz şaşırmadığım bir evrim örneği olarak görülüyor.

Karanlık programlama günlerinde, tek bir DOSYA'nın derlenmesi dakikalar alabilir. Bir program modülerleştirilmişse, gerekli başlık dosyalarının eklenmesi (önceden derlenmiş başlık seçenekleri yoktur) önemli bir ek yavaşlama nedeni olacaktır. Ek olarak, derleyici, muhtemelen otomatik bir takas dosyası kullanmadan, bazı bilgileri diskte tutmayı seçebilir / buna ihtiyaç duyabilir.

Bu çevresel faktörlerin devam eden kalkınma uygulamalarına aktardığı ve zaman içinde ancak yavaşça adapte olduğu alışkanlıklar.

Tek bir dosyayı kullanmanın kazandığı zaman, HDD'ler yerine SSD'leri kullandığımıza benzerdi.

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.