एक विशाल स्रोत फ़ाइल में कुछ C प्रोग्राम क्यों लिखे गए हैं?


88

उदाहरण के लिए, अतीत से SysInternals टूल "FileMon" में एक कर्नेल-मोड ड्राइवर है जिसका स्रोत कोड पूरी तरह से एक 4,000-लाइन फ़ाइल में है। पहले लिखे गए पिंग कार्यक्रम के लिए वही (~ 2,000 LOC)।

जवाबों:


143

कई फाइलों का उपयोग करने के लिए हमेशा अतिरिक्त प्रशासनिक ओवरहेड की आवश्यकता होती है। एक को अलग-अलग संकलन और लिंकिंग चरणों के साथ एक बिल्ड स्क्रिप्ट और / या मेकफाइल को सेटअप करना पड़ता है, सुनिश्चित करें कि विभिन्न फ़ाइलों के बीच निर्भरता सही तरीके से प्रबंधित की जाती है, ईमेल या डाउनलोड द्वारा स्रोत कोड के आसान वितरण के लिए "ज़िप" स्क्रिप्ट लिखें, और इसी तरह पर। आधुनिक आईडीई आज आम तौर पर बहुत अधिक बोझ उठाते हैं, लेकिन मुझे उस समय पूरा यकीन है जब पहला पिंग कार्यक्रम लिखा गया था, ऐसी कोई आईडीई उपलब्ध नहीं थी। और इस तरह की आईडीई के बिना ~ 4000 एलओसी के रूप में छोटी फ़ाइलों के लिए , जो आपके लिए अच्छी तरह से कई फ़ाइलों का प्रबंधन करता है, उल्लिखित ओवरहेड के बीच व्यापार बंद हो जाता है और कई फ़ाइलों का उपयोग करने से होने वाले लाभ लोगों को एकल फ़ाइल दृष्टिकोण के लिए निर्णय लेने दे सकते हैं।


9
"और ~ 4000 LOC के रूप में छोटी फ़ाइलों के लिए ..." मैं अभी जेएस देव के रूप में काम कर रहा हूं। जब मेरे पास कोड की सिर्फ 400 लाइनों की एक फाइल होती है, तो मुझे घबराहट होती है कि यह कितनी बड़ी हो गई है! (लेकिन हमारे पास हमारे प्रोजेक्ट में दर्जनों और दर्जनों फाइलें हैं।)
केविन

36
@ केविन: मेरे सिर पर एक बाल बहुत कम है, मेरे सूप में एक बाल बहुत अधिक है; जेएस की कई फाइलों में AFAIK कई प्रशासनिक अतिवृद्धि का कारण नहीं है जैसा कि "सी में एक आधुनिक आईडीई के बिना"।
Doc Brown

4
@ केविन जेएस हालांकि काफी अलग जानवर है। जेएस हर बार एक उपयोगकर्ता को एक वेबसाइट लोड करता है और यह पहले से ही उनके ब्राउज़र द्वारा कैश नहीं किया गया है। C को केवल एक बार कोड ट्रांसमिट करना होता है, फिर दूसरे छोर पर मौजूद व्यक्ति इसे संकलित करता है और यह संकलित रहता है (जाहिर है इसके अपवाद हैं, लेकिन यह सामान्य अपेक्षित उपयोग-मामला है)। साथ ही सी सामान विरासत कोड हो जाता है, क्योंकि normal 4000 लाइनें सामान्य है ’परियोजनाओं में से अधिकांश लोग टिप्पणियों में वर्णन कर रहे हैं।
फराप

5
@ केविन अब जाकर देखें कि कैसे अंडरस्कोर। Js (1700 लोकेशन, एक फाइल) और वितरित किए जाने वाले अन्य पुस्तकालयों के असंख्य लिखे जाते हैं। मॉडर्नाइजेशन और तैनाती के संबंध में जावास्क्रिप्ट वास्तव में लगभग उतना ही बुरा है जितना सी।
वू

2
@Pharap मुझे लगता है कि वह कुछ ऐसा का उपयोग कर मतलब Webpack कोड लागू करने से पहले। वेबपैक के साथ, आप कई फाइलों पर काम कर सकते हैं और फिर उन्हें एक बंडल में संकलित कर सकते हैं।
ब्रायन मैक्किऑन

81

क्योंकि C मॉड्यूलरराइजेशन में अच्छा नहीं है। यह गन्दा हो जाता है (हेडर फाइल और # पिनल, एक्सटर्नल फंक्शन, लिंक-टाइम एरर इत्यादि) और जितने अधिक मॉड्यूल आप इसमें लाते हैं, उतने ही अधिक चाल में हो जाता है।

अधिक आधुनिक भाषाओं में भाग में बेहतर मॉडर्नाइजेशन क्षमताएं हैं क्योंकि वे सी की गलतियों से सीखते हैं, और वे आपके कोडबेस को छोटी, सरल इकाइयों में तोड़ना आसान बनाते हैं। लेकिन सी के साथ, यह सब मुसीबत से बचने या कम से कम करने के लिए फायदेमंद हो सकता है, भले ही इसका मतलब है कि एक ही फाइल में बहुत अधिक कोड माना जाएगा।


38
मुझे लगता है कि सी दृष्टिकोण को 'गलतियों' के रूप में वर्णित करना अनुचित है; उस समय वे पूरी तरह से समझदार और उचित निर्णय लेने वाले थे।
जैक आइडली

14
उस modularisation सामान में से कोई भी विशेष रूप से जटिल नहीं है। इसे खराब कोडिंग शैली द्वारा जटिल बनाया जा सकता है , लेकिन इसे समझना या कार्यान्वित करना कठिन नहीं है, और इसमें से कोई भी "गलतियों" के रूप में वर्गीकृत नहीं किया जा सकता है। स्नोमैन के उत्तर के अनुसार वास्तविक कारण, कई स्रोत फ़ाइलों पर अनुकूलन अतीत में इतना अच्छा नहीं था, और उस फाइलमोन चालक को उच्च प्रदर्शन की आवश्यकता होती है। इसके अलावा, ओपी की राय के विपरीत, वे विशेष रूप से बड़ी फाइलें नहीं हैं।
ग्राहम

8
@ ग्राहम कोड की 1000 लाइनों से बड़ी किसी भी फाइल को कोड गंध माना जाना चाहिए।
मेसन व्हीलर

11
इसकी नहीं अनुचित @JackAidley सब पर , कुछ होने होना एक गलती हुए कहा कि यह समय में एक उचित फैसला था के साथ आपसी अनन्य नहीं है। गलतियाँ अनिवार्य रूप से दी गई अपूर्ण जानकारी और सीमित समय की होती हैं और चेहरे को बचाने के लिए शर्मनाक ढंग से छिपी हुई या पुनर्व्याख्या नहीं की जानी चाहिए।
जारेड स्मिथ

8
जो कोई भी दावा करता है कि सी का दृष्टिकोण कोई गलती नहीं है, यह समझने में विफल रहता है कि एक प्रतीत होता है कि दस-लाइनर सी फाइल वास्तव में सभी हेडर के साथ दस-हजार-लाइनर फ़ाइल हो सकती है #include: d। इसका मतलब है कि आपकी परियोजना की हर एक फाइल प्रभावी रूप से कम से कम दस हजार लाइनों की है, फिर चाहे वह लाइन "wc -l" द्वारा दी गई लाइन की संख्या ही क्यों न हो। प्रतिरूपकता के लिए बेहतर समर्थन आसानी से पार्सिंग और संकलन समय को एक छोटे से अंश में काट देगा।
जूहीस्ट

37

ऐतिहासिक कारणों के अलावा, आधुनिक प्रदर्शन-संवेदनशील सॉफ़्टवेयर में इसका उपयोग करने का एक कारण है। जब सभी कोड एक संकलन इकाई में होते हैं, तो कंपाइलर पूरे-कार्यक्रम अनुकूलन करने में सक्षम होता है। अलग संकलन इकाइयों के साथ, कंपाइलर पूरे प्रोग्राम को कुछ तरीकों से ऑप्टिमाइज़ नहीं कर सकता है (जैसे कुछ कोड को इनलाइन करना)।

लिंकर निश्चित रूप से संकलक क्या कर सकता है इसके अलावा कुछ अनुकूलन कर सकता है, लेकिन सभी नहीं। उदाहरण के लिए: आधुनिक लिंकर वास्तव में कई ऑब्जेक्ट फ़ाइलों में अपरिचित कार्यों को समाप्त करने में अच्छे हैं। वे कुछ अन्य अनुकूलन करने में सक्षम हो सकते हैं, लेकिन एक कंपाइलर एक फ़ंक्शन के अंदर क्या कर सकता है, ऐसा कुछ भी नहीं है।

एकल-स्रोत कोड मॉड्यूल का एक प्रसिद्ध उदाहरण SQLite है। आप SQLite समामेलन पृष्ठ पर इसके बारे में अधिक पढ़ सकते हैं ।

1 कार्यकारी सारांश

100 से अधिक अलग-अलग स्रोत फ़ाइलों को "sqlite3.c" नामक सी-कोड की एक बड़ी फ़ाइलों में समाहित किया गया है और "समामेलन" कहा जाता है। समामेलन में वह सब कुछ होता है जो किसी एप्लिकेशन को SQLite को एम्बेड करने के लिए आवश्यक होता है। समामेलन फ़ाइल 180,000 से अधिक लंबी और आकार में 6 मेगाबाइट से अधिक लंबी है।

SQLite के लिए सभी कोड को एक बड़ी फ़ाइल में मिलाने से SQLite को परिनियोजित करना आसान हो जाता है - इस पर नज़र रखने के लिए बस एक फ़ाइल होती है। और क्योंकि सभी कोड एक एकल अनुवाद इकाई में हैं, इसलिए कंपाइलर बेहतर अंतर-प्रक्रिया अनुकूलन कर सकते हैं, जिसके परिणामस्वरूप मशीन कोड 5% और 10% तेजी से होता है।


15
लेकिन ध्यान दें कि आधुनिक सी कंपाइलर कई स्रोत फ़ाइलों के पूरे-कार्यक्रम का अनुकूलन कर सकते हैं (हालांकि यदि आप उन्हें व्यक्तिगत ऑब्जेक्ट फ़ाइलों में पहले संकलित नहीं करते हैं)।
डेविस्लर

10
@ डेविडलाइपर विशिष्ट बिल्ड स्क्रिप्ट को देखें: कंपाइलर वास्तविक रूप से ऐसा नहीं करने जा रहे हैं।

4
यह एक निर्माण स्क्रिप्ट को बदलने के लिए काफी आसान $(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) $(CFILES)से एक एकल soudce फ़ाइल में सब कुछ स्थानांतरित करने के लिए है। तुम भी पूरे प्रोग्राम का संकलन पारंपरिक निर्माण स्क्रिप्ट के वैकल्पिक लक्ष्य के रूप में कर सकते हैं जो स्रोत फ़ाइलों को फिर से जमा करने में सक्षम नहीं है, जो कि उत्पादन लक्ष्य के लिए प्रोफाइलिंग और डीबगिंग को बंद करने के समान है। यदि आपके पास सब कुछ एक बड़े ढेर ओ के स्रोत में है तो आपके पास वह विकल्प नहीं है। ऐसा नहीं है कि लोगों को इस्तेमाल किया जाता है, लेकिन इसके बारे में कुछ भी बोझिल नहीं है।
डेविसलर

9
@Davislor संपूर्ण प्रोग्राम ऑप्टिमाइज़ेशन / लिंक-टाइम ऑप्टिमाइज़ेशन (LTO) भी तब काम करता है जब आप व्यक्तिगत ऑब्जेक्ट फ़ाइलों में कोड को "संकलित" करते हैं (यह निर्भर करता है कि "संकलन" आपके लिए क्या अर्थ है)। उदाहरण के लिए, GCC का LTO संकलित समय पर व्यक्तिगत ऑब्जेक्ट फ़ाइलों में अपने पार्स किए गए कोड प्रतिनिधित्व को जोड़ देगा, और लिंक समय में पूरे प्रोग्राम को फिर से संकलित करने और बनाने के लिए (वर्तमान भी) ऑब्जेक्ट कोड के बजाय एक का उपयोग करेगा। तो यह पहले व्यक्तिगत ऑब्जेक्ट फ़ाइलों के संकलन वाले बिल्ड सेटअप के साथ काम करता है, हालांकि प्रारंभिक संकलन द्वारा उत्पन्न मशीन कोड को अनदेखा किया जाता है।
सपने देखने

8
JsonCpp आजकल भी ऐसा करता है। कुंजी यह है कि विकास के दौरान फाइलें इस तरह से नहीं हैं।
ऑर्बिट

15

सादगी कारक के अलावा अन्य प्रतिवादी उल्लेख किया गया है, कई सी कार्यक्रम एक व्यक्ति द्वारा लिखे गए हैं।

जब आपके पास व्यक्तियों की एक टीम होती है, तो कोड परिवर्तनों में गंभीर संघर्षों से बचने के लिए एप्लिकेशन को कई स्रोत फ़ाइलों में विभाजित करना वांछनीय हो जाता है। खासकर तब जब प्रोजेक्ट पर काम करने वाले उन्नत और बहुत जूनियर प्रोग्रामर दोनों हों।

जब एक व्यक्ति खुद से काम कर रहा है, तो यह कोई मुद्दा नहीं है।

व्यक्तिगत रूप से, मैं एक आदत के रूप में फ़ंक्शन के आधार पर कई फ़ाइलों का उपयोग करता हूं। लेकिन वह सिर्फ मैं हूं।


4
@OskarSkog लेकिन आप अपने भविष्य के स्वयं के रूप में एक ही समय में एक फ़ाइल को संशोधित नहीं करेंगे।
लोरेन Pechtel

2

क्योंकि C89 में inlineफ़ंक्शन नहीं थे । जिसका मतलब था कि फंक्शंस में आपकी फ़ाइल को तोड़ने से स्टैक पर मूल्यों को धक्का देने और चारों ओर कूदने का ओवरहेड हो गया था। इसने 1 बड़े स्विच स्टेटमेंट (ईवेंट लूप) में कोड को लागू करने के लिए एक ओवरहेड का एक सा जोड़ा। लेकिन एक इवेंट लूप हमेशा अधिक मॉड्यूलर समाधान की तुलना में कुशलतापूर्वक (या सही ढंग से) लागू करने के लिए हमेशा अधिक कठिन होता है। बड़े आकार की परियोजनाओं के लिए, लोग अभी भी मॉड्यूलर करना पसंद करेंगे। लेकिन जब उनके पास डिजाइन पहले से सोचा हुआ था और 1 स्विच स्टेट में राज्य को नियंत्रित कर सकते थे, तो उन्होंने इसके लिए चुना।

आजकल, सी में भी, किसी को प्रदर्शन को संशोधित करने के लिए प्रदर्शन की आवश्यकता नहीं है क्योंकि यहां तक ​​कि सी फ़ंक्शन में भी इनलेट किया जा सकता है।


2
सी फंक्शंस इन दिनों 89 में सिर्फ इनलाइन के रूप में हो सकते हैं, इनलाइन एक ऐसी चीज है जिसका इस्तेमाल लगभग कभी नहीं किया जाना चाहिए - कंपाइलर लगभग सभी स्थितियों में आपसे बेहतर जानता है। और उन 4k LOC फ़ाइलों में से अधिकांश एक विशाल कार्य नहीं हैं - यह एक भयानक कोडिंग शैली है, जिसका कोई ध्यान देने योग्य लाभ भी नहीं होगा।
वू

@ हाँ, मुझे नहीं पता कि आप कोडिंग शैली का उल्लेख क्यों करते हैं। मैं इसकी वकालत नहीं कर रहा था। वास्तव में, मैंने उल्लेख किया है कि ज्यादातर मामलों में यह एक कुशल कार्यान्वयन के कारण कम कुशल समाधान की गारंटी देता है। मैंने यह भी उल्लेख किया कि यह एक बुरा विचार है क्योंकि यह बड़े प्रोजेक्ट्स के लिए नहीं है। कहा जा रहा है कि, बहुत तंग छोरों में (जो कि क्लोज-टू-हार्डवेयर नेटवर्किंग कोड में होता है), अनावश्यक रूप से पुश / पॉपिंग मानों को चालू / बंद स्टैक (जब कॉलिंग फ़ंक्शन) चालू कार्यक्रम की लागत में जोड़ देगा। यह एक महान समाधान नहीं था। लेकिन यह उस समय उपलब्ध सर्वश्रेष्ठ था।
दिमित्री रुबनोविच

2
अप्रचलित नोट: इनलाइन कीवर्ड का केवल इनलाइनिंग ऑप्टिमाइज़ेशन के साथ करना है। संकलक के लिए यह अनुकूलन करने के लिए एक विशेष संकेत नहीं है, इसके बजाय इसे डुप्लिकेट प्रतीकों के साथ जोड़ना है।
हाइड

@Dmitry बिंदु यह है कि यह दावा करते हुए कि क्योंकि inlineC89 संकलक में कोई कीवर्ड नहीं था, इनलाइन नहीं कर सकता था, यही कारण है कि आपको एक विशाल समारोह में सब कुछ लिखना पड़ा, गलत है। आपको inlineएक प्रदर्शन ऑप्टिमाइज़ेशन के रूप में बहुत अधिक कभी भी उपयोग नहीं करना चाहिए - कंपाइलर आमतौर पर आपको किसी भी तरह से बेहतर जानेंगे (और बस कीवर्ड को अनदेखा कर सकते हैं)।
वू

@Voo: एक प्रोग्रामर और एक कंपाइलर आमतौर पर प्रत्येक को कुछ चीजें पता होती हैं जो दूसरे नहीं करते हैं। inlineकीवर्ड लिंकर से संबंधित अर्थ विज्ञान जो या नहीं, इन-लाइन ऑप्टिमाइज़ेशन करने के सवाल से अधिक महत्वपूर्ण हैं है, लेकिन कुछ कार्यान्वयन में अस्तर नियंत्रित करने के लिए और इस तरह की चीजों कभी कभी बहुत महत्वपूर्ण हो सकता है अन्य निर्देशों की है। कुछ मामलों में, एक फ़ंक्शन ऐसा लग सकता है कि यह अस्तर के लायक होने के लिए बहुत बड़ा है, लेकिन निरंतर तह आकार और निष्पादन समय को लगभग कुछ भी नहीं घटा सकता है। एक संकलक जिसे अस्तर को प्रोत्साहित करने के लिए एक मजबूत कुहनी से हलका धक्का नहीं दिया जा सकता है ...
Supercat

1

यह विकास के एक उदाहरण के रूप में गिना जाता है, जो मुझे आश्चर्य है कि अभी तक इसका उल्लेख नहीं किया गया है।

प्रोग्रामिंग के अंधेरे दिनों में, एक एकल फ़ाइल का संकलन मिनट लग सकता है। यदि एक कार्यक्रम को संशोधित किया गया था, तो आवश्यक हेडर फ़ाइलों को शामिल करना (कोई पूर्वनिर्धारित हेडर विकल्प नहीं) मंदी का एक महत्वपूर्ण अतिरिक्त कारण होगा। इसके अतिरिक्त कंपाइलर डिस्क पर कुछ जानकारी रखने का विकल्प चुन सकता है।

इन पर्यावरणीय कारकों के कारण जो आदतें चल रही हैं वे विकास की प्रथाओं में ढल गई हैं और केवल समय के साथ धीरे-धीरे अनुकूलित हो गई हैं।

उस समय सिंगल फाइल का उपयोग करने से होने वाला लाभ HDD के बजाय SSDs के उपयोग से मिलता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.