2014-10-28 32 views
6

क्या यह कोड अपरिभाषित व्यवहार में परिणाम देगा?बाहरी "सी" इनलाइन फ़ंक्शन

header.h

#ifdef __cplusplus 
extern "C" 
{ 
#endif 

inline int foo(int a) 
{ 
    return a * 2; 
} 

#ifdef __cplusplus 
} 
#endif 

def.c

#include "header.h" 

extern inline int foo(int a); 

use.c

#include "header.h" 

int bar(int a) 
{ 
    return foo(a + 3); 
} 

main.cpp

#include <stdio.h> 
#include "header.h" 

extern "C" 
{ 
    int bar(int a); 
} 

int main(int argc, char** argv) 
{ 
    printf("%d\n", foo(argc)); 
    printf("%d\n", bar(argc)); 
} 

यह एक कार्यक्रम एक inline समारोह दोनों C और C++ में इस्तेमाल किया जाएगा, जहां की एक उदाहरण है। क्या यह काम करेगा यदि def.c हटा दिया गया था और foo सी में उपयोग नहीं किया गया था? जब साथ संकलित काम करता है (यह मानते हुए किया जाता है कि सी संकलक C99 है।)

इस कोड:

gcc -std=c99 -pedantic -Wall -Wextra -c -o def.o def.c 
g++ -std=c++11 -pedantic -Wall -Wextra -c -o main.o main.cpp 
gcc -std=c99 -pedantic -Wall -Wextra -c -o use.o use.c 
g++ -std=c++11 -pedantic -Wall -Wextra -o extern_C_inline def.o main.o use.o 

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

+0

क्या सी भी 'इनलाइन' कीवर्ड को पहचानता है? मैंने सोचा कि वे इसे अलग-अलग जादू करते हैं। –

+5

@BenVoigt: हां, हालांकि इसमें थोड़ा अलग अर्थशास्त्र है। – Deduplicator

+0

मुझे नहीं पता कि मैंने क्यों सोचा था कि सी संस्करण में कुछ अंडरस्कोर था। –

उत्तर

5

कार्यक्रम लिखित के रूप में मान्य है, लेकिन def.c यह सुनिश्चित करने के लिए आवश्यक है कि कोड हमेशा सभी कंपाइलरों के साथ काम करता है और विभिन्न फ़ाइलों के लिए अनुकूलन स्तरों का संयोजन करता है।

$ nm def.o 
0000000000000000 T foo 

यही परिभाषा हमेशा चाहे कितना कि def.o में मौजूद रहेंगे:

क्योंकि वहाँ extern उस पर के साथ एक घोषणा है, def.c समारोह foo(), जो आप nm साथ पुष्टि कर सकते हैं की एक बाहरी परिभाषा प्रदान करता है फ़ाइल संकलित है।

use.c में एक इनलाइन परिभाषा foo() की वहाँ है, लेकिन सी मानक में 6.7.4 के अनुसार यह अनिर्दिष्ट है foo() करने के लिए कॉल कि इनलाइन परिभाषा का उपयोग करता है या एक बाहरी परिभाषा (व्यवहार में है कि क्या यह का उपयोग करता है का उपयोग करता है इनलाइन परिभाषा इस बात पर निर्भर करती है कि फ़ाइल अनुकूलित है या नहीं)। यदि संकलक इनलाइन परिभाषा का उपयोग करना चुनता है तो यह काम करेगा। यदि यह इनलाइन परिभाषा का उपयोग न करने का विकल्प चुनता है (उदा। क्योंकि इसे ऑप्टिमाइज़ेशन के बिना संकलित किया गया है) तो आपको किसी अन्य फ़ाइल में बाहरी परिभाषा की आवश्यकता है।

$ gcc -std=c99 -pedantic -Wall -Wextra -c -o use.o use.c 
$ nm use.o 
0000000000000000 T bar 
       U foo 

लेकिन अनुकूलन के साथ ऐसा नहीं होता:

अनुकूलन use.o बिना एक अपरिभाषित संदर्भ है

$ gcc -std=c99 -pedantic -Wall -Wextra -c -o use.o use.c -O3 
$ nm use.o 
0000000000000000 T bar 

main.cpp में foo() की एक परिभाषा हो जाएगा, लेकिन यह आम तौर पर एक कमजोर उत्पन्न होगा प्रतीक, इसलिए यह किसी अन्य ऑब्जेक्ट में दूसरी परिभाषा पाई जाने पर लिंकर द्वारा नहीं रखा जा सकता है। कमजोर प्रतीक मौजूद है, तो यह है कि एक बाहरी परिभाषा की आवश्यकता है use.o में किसी भी संभावित संदर्भ संतुष्ट कर सकते हैं, लेकिन अगर संकलक inlines main.o में foo() तो यह main.o में foo() के किसी भी परिभाषा उत्सर्जन नहीं हो सकता है, और इसलिए def.o में परिभाषा अभी भी जरूरत होगी

$ g++ -std=c++11 -pedantic -Wall -Wextra -c -o main.o main.cpp 
$ nm main.o 
       U bar 
0000000000000000 W foo 
0000000000000000 T main 
       U printf 

हालांकि संकलन main.cpp-O3 साथ foo और वें के लिए कॉल inlines: use.o

को पूरा करने के अनुकूलन main.o बिना एक कमजोर प्रतीक शामिल ई संकलक इसके लिए किसी भी प्रतीक उत्सर्जन नहीं:

$ g++ -std=c++11 -pedantic -Wall -Wextra -c -o main.o main.cpp -O3 
$ nm main.o 
       U bar 
0000000000000000 T main 
       U printf 

तो अगर foo()use.o में inlined नहीं लेकिन तो main.o में inlined है आप def.o

में बाहरी परिभाषा की जरूरत है सकते हैं यह है अगर def.c हटा दिया गया था और सी में foo का उपयोग नहीं किया गया था तो काम करें?

हां। यदि foo केवल सी ++ फ़ाइल में उपयोग किया जाता है तो आपको foo की def.o में बाहरी परिभाषा की आवश्यकता नहीं है क्योंकि main.o या तो अपनी स्वयं की (कमजोर) परिभाषा है या फ़ंक्शन को रेखांकित करेगी। foo.o में परिभाषा केवल अन्य सी कोड से foo पर गैर-इनलाइन कॉल को संतुष्ट करने की आवश्यकता है।


एक तरफ

: C++ कम्पाइलर जब main.o के अनुकूलन foo के लिए किसी भी प्रतीक पैदा क्योंकि सी ++ मानक का कहना है कि एक समारोह एक अनुवाद इकाई में inline घोषित सभी अनुवाद इकाइयों में इनलाइन घोषित किया जाना चाहिए छोड़ करने की अनुमति दी है, और एक समारोह को कॉल करने के लिए inline परिभाषा कॉल के समान फ़ाइल में उपलब्ध होना चाहिए। इसका मतलब है कि संकलक जानता है कि अगर कोई अन्य फ़ाइल foo() पर कॉल करना चाहती है तो उस अन्य फ़ाइल में foo() की परिभाषा होनी चाहिए, और इसलिए जब उस अन्य फ़ाइल को संकलित किया गया है तो संकलक फ़ंक्शन की एक और कमजोर प्रतीक परिभाषा उत्पन्न करने में सक्षम होगा (या जरूरत के रूप में इनलाइन)। main.o में सभी कॉलों को रेखांकित किया गया है तो main.o में foo आउटपुट करने की आवश्यकता नहीं है।

इन सी, जहां use.c में इनलाइन परिभाषा संकलक द्वारा अनदेखा किया जा सकता से differnet अर्थ विज्ञान रहे हैं, और def.o में बाहरी परिभाषा भले ही def.c में कुछ भी नहीं कहता मौजूद होना चाहिए।

+0

यह जवाब देने के लिए पर्याप्त नहीं है कि _ "इसमें कोई सी संकलक शामिल नहीं है" _ क्योंकि बिंदु _C linkage_ है, _C compiler_ नहीं है, और यहां तक ​​कि 'बाहरी "सी में लिखा गया कोड भी एक C++ संकलक द्वारा संकलित हो जाता है ? – user2485710

+1

@ user2485710, क्योंकि यह सच नहीं है। 'def.c' और' use.c' को एक संकलक द्वारा संकलित किया गया है। –

+0

@ जोनाथन वाकई यकीन है, लेकिन एक प्रश्न में जो 'बाहरी "सी' 'से शुरू होता है, जो एक सी ++ केवल निर्माण करता है, यह चीज़ सादा' सी 'कंपाइलर के साथ कितनी बार संकलित की जाएगी? मुझे लगता है कि सवाल इस तथ्य से प्रभावित है कि ओपी यह मान रहा है कि सी ++ कोड बेस में उस कोड का उपयोग करते समय भी इसे एक सी संकलक द्वारा संकलित किया जाता है। – user2485710

संबंधित मुद्दे