2009-08-07 6 views
10

मैं निम्नलिखित सी ++ प्रोग्रामसी हेडर फाइलें बाइनरी के आकार को क्यों नहीं बढ़ाती हैं?

class MyClass { 
public: 
     int i; 
     int j; 
     MyClass() {}; 
}; 

int main(void) 
{ 
     MyClass inst; 
     inst.i = 1; 
     inst.j = 2; 
} 

और मैं संकलित लिखा था।

# g++ program.cpp 
# ls -l a.out 
-rwxr-xr-x 1 root wheel 4837 Aug 7 20:50 a.out 

फिर, मैं स्रोत फ़ाइल में हेडर फाइल iostream d #include और मैं फिर से संकलित।

# g++ program.cpp 
# ls -l a.out 
-rwxr-xr-x 1 root wheel 6505 Aug 7 20:54 a.out 

फ़ाइल आकार, अपेक्षित के रूप में, बढ़ाया गया था।

मैं भी निम्नलिखित सी कार्यक्रम

int main(void) 
{ 
    int i = 1; 
    int j = 2; 
} 

लिखा था और मैं

# gcc program.c 
# ls -l a.out 
-rwxr-xr-x 1 root wheel 4570 Aug 7 21:01 a.out 

संकलित फिर, मैं हेडर फाइल stdio.h d #include और मैं फिर से

# gcc program.c 
# ls -l a.out 
-rwxr-xr-x 1 root wheel 4570 Aug 7 21:04 a.out 

संकलित विचित्र रूप से पर्याप्त, निष्पादन योग्य फाइलों का आकार वही बना रहा।

उत्तर

18

अपनी स्रोत फ़ाइल में iostream सहित, संकलक को C++ मानक I/O लाइब्रेरी को सेटअप और फाड़ने के लिए कोड उत्पन्न करने की आवश्यकता है। संकलक द्वारा द्वारा

$ nm --demangle test_with_iostream 
08049914 d _DYNAMIC 
08049a00 d _GLOBAL_OFFSET_TABLE_ 
08048718 t global constructors keyed to main 
0804883c R _IO_stdin_used 
     w _Jv_RegisterClasses 
080486d8 t __static_initialization_and_destruction_0(int, int) 
08048748 W MyClass::MyClass() 
     U std::string::size() [email protected]@GLIBCXX_3.4 
     U std::string::operator[](unsigned int) [email protected]@GLIBCXX_3.4 
     U std::ios_base::Init::Init()@@GLIBCXX_3.4 
     U std::ios_base::Init::~Init()@@GLIBCXX_3.4 
080485cc t std::__verify_grouping(char const*, unsigned int, std::string const&) 
0804874e W unsigned int const& std::min<unsigned int>(unsigned int const&, unsigned int const&) 
08049a3c b std::__ioinit 
08049904 d __CTOR_END__ 
... (remaining output snipped) ... 

(--demangle सी ++ फ़ंक्शन नाम "घायल" लेता है और अधिक सार्थक पैदा करता है: आप nm से उत्पादन है, जो प्रतीकों (आम तौर पर काम करता है) अपने वस्तु फ़ाइल पर चलता देख कर यह देख सकते नाम। पहला कॉलम पता है, यदि फ़ंक्शन निष्पादन योग्य में शामिल है। दूसरा कॉलम प्रकार है। "टी" "टेक्स्ट" सेगमेंट में कोड है। "यू" अन्य स्थानों से जुड़े प्रतीक हैं; इसमें केस, सी ++ साझा लाइब्रेरी से।)

iostream:

सहित आपकी स्रोत फ़ाइल से उत्पन्न कार्यों के साथ इसकी तुलना करें
$ nm --demangle test_without_iostream 
08049508 d _DYNAMIC 
080495f4 d _GLOBAL_OFFSET_TABLE_ 
080484ec R _IO_stdin_used 
     w _Jv_RegisterClasses 
0804841c W MyClass::MyClass() 
080494f8 d __CTOR_END__ 
... (remaining output snipped) ... 

जब आपकी स्रोत फ़ाइल में iostream शामिल था, तो संकलक ने कई कार्यों को iostream के बिना प्रस्तुत नहीं किया।

जब आपके स्रोत फ़ाइल केवल stdio.h भी शामिल है, उत्पन्न द्विआधारी के बाद से सी मानक मैं/हे पुस्तकालय के ऊपर और क्या पहले से ही सी गतिशील पुस्तकालय में हो रहा है से परे किसी भी अतिरिक्त आरंभीकरण की जरूरत नहीं है, iostream बिना परीक्षण के समान है। आप इसे nm आउटपुट देखकर देख सकते हैं, जो समान है।

सामान्य रूप से, निष्पादन योग्य के आकार के आधार पर किसी विशेष स्रोत फ़ाइल द्वारा उत्पन्न कोड की मात्रा के बारे में जानकारी का उपयोग करने की कोशिश करना अर्थपूर्ण नहीं होगा; वहां बहुत अधिक परिवर्तन हो सकता है, और स्रोत फ़ाइल के स्थान जैसी साधारण चीजें बाइनरी बदल सकती हैं यदि कंपाइलर में डिबगिंग जानकारी शामिल है।

आप अपने निष्पादन योग्य सामग्री की सामग्री पर चारों ओर पोकिंग के लिए objdump उपयोगी भी पा सकते हैं।

7

iostream कोड शामिल है। stdio.h नहीं करता है।

अधिक विशेष रूप से, निम्नलिखित परिभाषा iostream में (वहाँ सूचीबद्ध की तुलना में अधिक हैं, और संकलक के हिसाब से बदलती) मानक लाइब्रेरी में बनाए संदर्भ वस्तुओं, जो तब अपने कोड में जुड़े हुए हैं:

extern istream &cin; 
extern ostream &cout; 
extern ostream &cerr; 
extern ostream &clog; 
+2

'बाहरी' परिभाषा कोड उत्पन्न नहीं करती है; वे सिर्फ कंपाइलर को जानते हैं कि वे मौजूद हैं, इसलिए यदि संकलक वास्तव में उपयोग किए जाते हैं तो संकलक उन्हें संदर्भित कर सकते हैं। – bdonlan

+0

हां - एक मूल्यवान स्पष्टीकरण। –

+0

मुझे नहीं लगता कि वे 'बाहरी' हैं - और यहां तक ​​कि यदि वे हैं, तो कुछ परिभाषाएं होनी चाहिए। निष्पादन योग्य आकार में वृद्धि के लिए उनके ctors/dtors एक (शायद एकमात्र) कारण हैं। – sbi

9

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

संपादित करें: इसमें इनलाइन फ़ंक्शंस, कक्षाएं और अन्य शामिल हो सकते हैं, जिनमें कोड शामिल है, लेकिन इसका परिणाम आपके निष्पादन योग्य आकार में तब तक नहीं बढ़ना चाहिए जब तक वे वास्तव में उपयोग नहीं किए जाते।

+1

हाँ, लेकिन यह स्पष्ट नहीं करता है कि '' निष्पादन योग्य आकार क्यों बढ़ाता है। – sbi

2

आमतौर पर, हेडर फ़ाइलों में संकलक के लिए केवल जानकारी होती है, वास्तविक कोड नहीं। उदाहरण के लिए:

ऐसा
struct foo { 
    int x; 
}; 

संरचना परिभाषाओं अक्सर हेडर में दिखाई देते हैं, लेकिन वे वास्तव में कोड का कारण नहीं है उत्पन्न करने के रूप में वे केवल कैसे 'foo' संभाल करने के बारे में जानकारी देने के संकलक, यह देखना चाहिए बाद में। अगर यह foo नहीं देखता है, तो संकलन समाप्त होने पर जानकारी खो जाती है।

वास्तव में, कुछ भी उत्पन्न करता है जो कोड उत्पन्न करता है आमतौर पर एक त्रुटि उत्पन्न करेगा। उदाहरण के लिए:

void foo() { 
    printf("bar!\n"); 
} 

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

ध्यान दें कि यहां एक अपवाद सी ++ में इनलाइन सदस्यों है।उदाहरण के लिए:

class Foo { 
    void bar() { /* ... */ } 
}; 

तकनीकी रूप से बोलने वाली बार() इस फ़ाइल को शामिल करने वाली प्रत्येक फ़ाइल में उत्पन्न होती है। संकलक त्रुटि से बचने के लिए विभिन्न चाल करता है (कमजोर बाध्यकारी, आदि)। यह वास्तव में निष्पादन योग्य के आकार को बढ़ा सकता है, और शायद आपने <iostream> के साथ देखा है।

3

iostream में कुछ स्थिर प्रारंभिकताएं हैं, जबकि stdio.h में केवल कार्य और उनकी परिभाषाएं हैं। इसलिए iostream सहित अधिक आकार के निष्पादन योग्य उत्पादन होगा।

std :: अदालत, std :: cerr, std :: CIN जो ostream प्रकार हैं:

0

iostream फ़ाइल कुछ वैश्विक वस्तुओं की घोषणा की।

तब संकलक उस वर्ग को लाएगा और इसे आपके अंतिम बाइनरी में संकलित करेगा, जो इसके आकार में इतना जोड़ देगा।

1

<iostream> हैडर एसटीडी वस्तुओं की एक जोड़ी, ':: , 'std::cout, std::cerr, और std::clog CIN साथ आता है। ये उन वर्गों के उदाहरण हैं जिनमें गैर-तुच्छ रचनाकार और विनाशक हैं। ये कोड हैं और उन्हें लिंक करना होगा। यह निष्पादन योग्य आकार को बढ़ाता है।

AFAIK, <cstdio> कोड के साथ नहीं आता है, इसलिए इसीलिए निष्पादन योग्य आकार में कोई वृद्धि नहीं हुई है।